UITableView 视频自动播放功能总结

5,708 阅读5分钟

概述

最近应项目需求,实现在 tableView中添加视频自动播放功能,产品功能类似与微博的视频信息流播放样式,为此实现了好一段时间,现在把当初实现的方法以及内容记录于此,以便后续回顾以及查看。

思路

视频屏幕居中播放

因为之前没有做过这样的功能,所以也是做了不少调研工作,因为微博的视频很具有代表性,所以以此为研究对象,构思了一下相关的播放逻辑内容。

微博视频自动播放

注意到微博视频播放是居中位置播放,也就是说距离中心位置最近的视频播放 cell 进行自动播放,而其他 cell 中的视频处于停止状态,显然这是一个屏幕居中选定视频的一个算法,而这个算法也这是控制视频播放的核心内容。为此实现它也有了相应的思路,而这块内容大致可以分为三个步骤:

  1. 找出当前屏幕中已经正在显示的 cell,用数组存起来
  2. 在数组中找出距离屏幕中央最近的 cell
  3. 存储第二个步骤中找出的 cell(牵扯到后续播放以及停止)

使用单例进行视频的有序播放

仔细看了一下微博的视频播放,会发现信息流中的视频始终都是一个视频在播放,无论怎么滑动,都是一个视频在当前播放,我想这么做无疑也是两点,一是保证视频播放的唯一性,二则是减少内存的占用。如果每个 cell 中都添加一个视频播放器的话,也会占用不少内存吧。还有一点就是,如果设计成单例进行视频播放的话,整个信息流中视频播放体系就会变得很好控制,逻辑也会变得愈发清晰。所以这种情况下的视频播放设计成单例播放无疑是最好的选择。

控制滚动判断视频播放的时机

因为要不断的找出在屏幕中显示的 cell,以及要比较出当前离屏幕中最近的视频cell,所以这个过程如果放在 tableView 中的 didScrollview 方法中判断的话,会在滑动的时候疯狂比较查找,这样做显然是不好的。所以滚动过程中我们尽量不去判断这些逻辑,在滚动停止的时候再去触发判断的逻辑,这样既能够满足自动播放的功能,也省去了来回比较的逻辑过程。所以我们可以在 tableview 的scrollViewDidEndDraggingscrollViewDidEndDecelerating回调中进行判断。

实现

有了思路,接下来就是实现了,其实实现方式多种多样,重在思想。

视频屏幕居中播放

该功能的实现实际上主要在于找到当前屏幕中距离屏幕中线距离最近的 cell,然后选中 cell,让其进行播放也就达到了播放的目的,代码如下:

/* 进行视频自动播放判定逻辑判断 */
- (void)handleScrollPlay{
    
    LCVideoCell *cell = (LCVideoCell *)[self getMinCenterCell];
    
    if (cell && ![self.playingCell isEqual:cell]) {
        
        NSLog(@"当前的 cell 存在,是%ld",cell.tag);
        cell.backgroundColor = [UIColor redColor];
        
        if (self.playingCell) {
            LCVideoCell *playingCell = (LCVideoCell *)self.playingCell;
            playingCell.backgroundColor = [UIColor whiteColor];
        }
        
        self.playingCell = cell;
        
    }
    
    
    
}

/* 获取距离屏幕最中间的cell */
- (id)getMinCenterCell{
    
    CGFloat minDelta = CGFLOAT_MAX;
    
    //屏幕中央位置
    CGFloat screenCenterY = SCREEN_HEIGHT * 0.5;
    //当前距离屏幕中央最近的cell
    id minCell = nil;
    
    for (id cell in self.visibleCells) {
        
        if ([cell isKindOfClass:[LCVideoCell class]]) {
            
            LCVideoCell *videoCell = (LCVideoCell *)cell;
            //获取当前 cell 的居中点坐标
            CGPoint cellCenterPoint = CGPointMake(videoCell.frame.origin.x, videoCell.frame.size.height * 0.5 + videoCell.frame.origin.y);
            //转换当前的 cell 的坐标
            CGPoint coorPoint = [videoCell.superview convertPoint:cellCenterPoint toView:nil];
            CGFloat deltaTemp =  fabs(coorPoint.y - screenCenterY);
            
            if (deltaTemp < minDelta) {
                minCell = videoCell;
                minDelta = deltaTemp;
            }
            
        }
        
    }
    
    return minCell;
    
}


判断当前的播放的 cell 是否已经移动到屏幕外面

这个判断逻辑主要是实现在移出到屏幕外之后,视频应该停止的功能,所以为此我们需要写一个方法去判断当前播放的 cell 的可见性。以及在滚动图中实时判断当前的播放的cell是否已经移动到屏幕外面。判断的代码如下:

/* 当前播放的视频是否划出屏幕 */
- (BOOL)playingCellIsOutScreen{

    if (!self.playingCell) {
        
        return YES;
    }
    
    LCVideoCell *videoCell = (LCVideoCell *)self.playingCell;
    
    //当前显示区域内容
    CGRect visiableContentZone = [UIScreen mainScreen].bounds;
    
    //向上滚动
    if(self.scrollDirection == LC_SCROLL_UP){
        
        //找到滚动时候的正在播放视频的cell底部的y坐标点,计算出当前播放的视频是否移除到屏幕外
        CGRect playingCellFrame = videoCell.frame;
        
        //当前正在播放视频的坐标
        CGPoint cellBottomPoint = CGPointMake(playingCellFrame.origin.x, playingCellFrame.size.height + playingCellFrame.origin.y);
        
        //坐标系转换(转换到 window坐标)
        CGPoint coorPoint = [videoCell.superview convertPoint:cellBottomPoint toView:nil];
        
        return CGRectContainsPoint(visiableContentZone, coorPoint);
        
        
    }
    
    //向下滚动
    else if(self.scrollDirection == LC_SCROLL_DOWN){
        
        //找到滚动时候的正在播放视频的cell底部的y坐标点,计算出当前播放的视频是否移除到屏幕外
        CGRect playingCellFrame = videoCell.frame;
        
        //当前正在播放视频的坐标
        CGPoint orginPoint = CGPointMake(playingCellFrame.origin.x, playingCellFrame.origin.y);
        
        //坐标系转换(转换到 window坐标)
        CGPoint coorPoint = [videoCell.superview convertPoint:orginPoint toView:nil];
        
        return CGRectContainsPoint(visiableContentZone, coorPoint);
        
    }
    
    else{
        
        return NO;
    }
    
    
    return YES;
}

效果

视频自动选择播放的效果如下所示

总结

视频的居中播放思想就是这样,当然播放器以及网络的判断应该是播放器播放内部的处理方案了,希望能够给正在开发或者想要开发视频自动选择播放的同学们一点小小的启发。

Demo

Demo 点我