美文网首页
弹幕容器和手势:LNDanmakuContainerView

弹幕容器和手势:LNDanmakuContainerView

作者: BangRaJun | 来源:发表于2021-02-05 22:26 被阅读0次

    这篇文章的前置文章:LNDanmakuMaster

    弹幕容器通常需要覆盖在播放器视图上面,容器需要响应那些有弹幕区域的手势,透传那些没有弹幕区域的手势;如果希望使用CALayer系列组件做动效就需要额外处理手势,因为通常CALayer是不能响应手势,所以,我将这些繁琐的处理封装成ContainerView进行统一处理。

    处理后的ContainerView有如下特性:

    • 使用统一的一个TapGesture代替为每条弹幕都添加一个TapGesture。
    • 触碰那些没有弹幕UI的区域时,手势会被透传到底层。
    • 弹幕的presentView支持自定义手势,没有自定义手势时,走ContainerView默认的Tap手势,事件通过代理传出去。
    • 弹幕的presentLayer只支持默认的Tap手势,事件通过代理传出去。
    • 实现了TrackController的装载、卸载方法。

    hitTest函数是ContainerView处理手势的核心代码:

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
        if (self.hidden) {
            return [super hitTest:point withEvent:event];
        }
        for (CALayer *layer in [self.layer.sublayers reverseObjectEnumerator]) {
            if ([layer hitTest:point]) {
                if (layer.danmakuAttributes) {
                    return self;
                } else {
                    return [super hitTest:point withEvent:event];
                }
                break;
            }
        }
        return nil;
    }
    
    

    判断流程如下:

    • 如果自身被隐藏,不响应任何手势。
    • 遍历containerView.Layer上的所有子Layer
    • 如果Layer上能找到弹幕信息,说明这个Layer是个独立的Layer,可以直接响应弹幕点击事件,所以直接返回self,用自己的tap手势处理。
    • 如果Layer上找不到弹幕信息,说明这个Layer是通过addSubView添加的Layer,弹幕信息绑定在它的View上;这样直接走View层级的手势判断:如果弹幕自己的View有自定义手势则响应自定义手势,没有会响应containerView的tap手势。
    • 如果没有找到子View响应手势,那ContainerView自身也不会响应,返回nil,手势透传到下一层级。

    注:倒序遍历,因为调用addSubview/addSubLayer在不刻意设置zPosition时,后加入的View/Layer通常覆盖在前面加入的View/Layer上,所以,倒序遍历的结果会更符合用户视觉上的认知。

    用户触发手势后走didTapped函数,这个函数的主要工作目标是找到Attributes并通过代理把这个事件传出去:

    - (void)didTapped:(UITapGestureRecognizer *)tap
    {
        CGPoint point = [tap locationInView:self];
        CALayer *tappedLayer = nil;
        UIView *tappedView = nil;
        for (CALayer *layer in [self.layer.sublayers reverseObjectEnumerator]) {
            if ([layer hitTest:point]) {
                if (layer.danmakuAttributes) {
                    tappedLayer = layer;
                } else {
                    if ([layer.delegate isKindOfClass:[UIView class]]) {
                        tappedView = (UIView *)layer.delegate;
                    }
                }
                break;
            }
        }
    
        LNDanmakuAbstractAttributes *targetAttributes;
        if (tappedLayer) {
            targetAttributes = [tappedLayer danmakuAttributes];
        } else if (tappedView) {
            targetAttributes = [tappedView danmakuAttributes];
        }
        
        if (targetAttributes && self.delegate && [self.delegate respondsToSelector:@selector(danmakuContainerDidTappedAttributes:)]) {
            [self.delegate danmakuContainerDidTappedAttributes:targetAttributes];
        }
    }
    
    

    (这里应该先判断是否有代理,没有代理可以直接return,免得做多余的计算,之后改一下)

    建议:除了弹幕视图之外最好不要在containerView上加其他的视图,加在containerView的父视图上。

    相关文章

      网友评论

          本文标题:弹幕容器和手势:LNDanmakuContainerView

          本文链接:https://www.haomeiwen.com/subject/aetntltx.html