You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在UITableViewCell中正确展示AVPlayerViewController?

解决UITableViewCell中AVPlayerViewController点击触发cell选中的问题

这个问题我之前做视频列表业务时也碰到过,本质是触摸事件穿透了AVPlayerViewController的视图,传递到下方的UITableViewCell,从而触发了tableView:didSelectRowAtIndexPath:回调。下面给你几个实用的解决思路:

方法一:直接禁用Cell的选中状态(适合不需要选中效果的场景)

如果你的Cell本来就不需要点击选中的交互,最简单的办法就是禁用它的选中样式:

// 可以在自定义Cell的awakeFromNib或者初始化方法里设置
self.selectionStyle = UITableViewCellSelectionStyleNone;

// 或者在tableView:cellForRowAtIndexPath:中配置Cell时设置
cell.selectionStyle = UITableViewCellSelectionStyleNone;

这种方式零成本,但如果你的Cell还有其他需要选中的业务场景,就不太适用了。

方法二:让AVPlayerViewController的视图拦截触摸事件

这是更灵活的方案,核心是确保播放器的视图能正确承接触摸事件,不让事件往下透传给Cell。

子方案1:给播放器视图添加透明遮罩(快速实现)

在你展示播放器的方法里,给AVPlayerViewController的view加一个覆盖整个区域的透明UIView,让它来接收触摸事件:

-(void)showVideoInView:(UIView *)view URL:(NSURL *)url {
    if (!url || !view) {
        return;
    }
    AVPlayerViewController *playerVC = [[AVPlayerViewController alloc] init];
    playerVC.player = [AVPlayer playerWithURL:url];
    playerVC.view.frame = CGRectIntegral(view.bounds);
    
    // 添加透明遮罩,拦截触摸事件
    UIView *touchMask = [[UIView alloc] initWithFrame:playerVC.view.bounds];
    touchMask.userInteractionEnabled = YES;
    touchMask.backgroundColor = [UIColor clearColor];
    // 注意要把遮罩放在播放器控制条的下层,避免挡住控制交互
    [playerVC.view insertSubview:touchMask atIndex:0];
    
    [self addChildViewController:playerVC];
    [view addSubview:playerVC.view];
    [playerVC didMoveToParentViewController:self];
    [playerVC.player play];
}

这里要注意遮罩的层级,插在最底层就不会影响播放器控制条的交互,同时能拦截透传的触摸事件。

子方案2:自定义AVPlayerViewController子类(更优雅)

创建一个AVPlayerViewController的子类,重写它的view的hitTest:withEvent:方法,确保触摸事件被正确拦截:

@interface CustomPlayerVC : AVPlayerViewController
@end

@implementation CustomPlayerVC

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *hitView = [super hitTest:point withEvent:event];
    // 如果触摸点不在播放器的控制元素上,就让当前view承接事件,阻止透传
    if (!hitView || hitView == self.view) {
        return self.view;
    }
    // 控制元素的触摸正常响应
    return hitView;
}

@end

然后在你的展示方法里替换成这个子类:

-(void)showVideoInView:(UIView *)view URL:(NSURL *)url {
    if (!url || !view) {
        return;
    }
    CustomPlayerVC *playerVC = [[CustomPlayerVC alloc] init];
    playerVC.player = [AVPlayer playerWithURL:url];
    playerVC.view.frame = CGRectIntegral(view.bounds);
    
    [self addChildViewController:playerVC];
    [view addSubview:playerVC.view];
    [playerVC didMoveToParentViewController:self];
    [playerVC.player play];
}

这种方式既不会影响播放器控制条的正常交互,又能彻底阻止事件透传到Cell,是我最推荐的方案。

方法三:在didSelectRow里判断点击区域(兜底方案)

如果上面的方法都不适合你的场景,还可以在tableView:didSelectRowAtIndexPath:里判断点击的是不是播放器区域,是的话就跳过选中逻辑:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    // 假设你的播放器容器视图是cell的某个子视图,比如cell.playerContainerView
    UIView *playerContainer = cell.playerContainerView;
    CGPoint touchPoint = [tableView convertPoint:[[tableView touchesForEvent:nil] anyObject].locationInView:tableView toView:playerContainer];
    
    if (CGRectContainsPoint(playerContainer.bounds, touchPoint)) {
        // 点击的是播放器区域,取消选中并返回
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        return;
    }
    
    // 这里处理正常的Cell选中逻辑
}

不过这种方式需要处理触摸点的转换,相对麻烦一些,适合临时兜底用。

内容的提问来源于stack exchange,提问作者BaQiWL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:10:47