iOS事件处理——Swift & Objective-C 表述

怎样选择最合适处理事件的控件

  • 当用户点击屏幕后,产生2个参数 一个touches 保存用户点击的 UITouch对象到 NSSet 中,和一个事件对象UIEvent ,并且加入到UIApplication 对象的事件处理Loop中队列

  • 由UIApplication查看,当前有没有堵塞,如果没有就将事件分发下去,一般是交给主窗口,keyWindow

  • 然后Window 会用 下面的这个方法

 //Swift
func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? 

//Objective-C
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
 
  • 该方法是用于查询当前最佳处理事件的控件,如果我们重写window的这个方法后,其他view的触摸事件没受影响,那么说明我们的思路是对的,废话不多说,代码带注释

Swift

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {

        /*1.判断自己可不可以与用户交互满足一下几点
        1.self.userInteractionEnabled = YES 可以与用户交互
        2.self.hidden = NO 不是隐藏的
        3.self.alpha > 0.01 透明度大于 0.01 也就是用户可见
        */

        //下面是写的上面的反面
        if self.userInteractionEnabled == false || self.hidden == true || self.alpha <= 0.01 {
            return nil
        }

        /*2.这里查看这个点是不是在控件的bound上了,如果不在就返回nil */

        if self.pointInside(point, withEvent: event) == false { return nil }


        /*3.遍历 子控件,由于addSubView 本身是把图层加到另
        一个图层上面,导致图层的顺序是最后添加的在最上面,也就是
        上面说的,后面加入的控件可能会在盖住,前面加入的控件图
        层,而响应链是优先最上面的图层的,考虑到这个递归算法是 
        DFS 也就是深度优先,所以必须从后面的子控件遍历
        */


        //3.1得到子控制总个数
        let count = Int(self.subviews.count) - 1


        for var i = count ; i >= 0 ; --i  {

            //1.得到子控件
            let childView:UIView = self.subviews[i]

            /*2,将父控件的坐标点转换到子控件中的形式,其实就拿
            子控件在父控件的frame的x,y ,与用户触点的父控件的
            x,y,进行减法*/

            let childPoint = self.convertPoint(point, toView: childView)

            //3.继续递归
            let firstView = childView.hitTest(childPoint, withEvent: event)

            //4.发现不为空,就回传
            if let notEmpty = firstView {
                return notEmpty
            }
            
        }
        //5.如果没知道合适的处理事件控件,就返回自己
        return self
        
    }
 
  • 上面说的自己写self.convertPoint(point, toView: childView)这方法,其实就是下面的算法
func myConvertPoint(point:CGPoint, toView view:UIView) -> CGPoint {

        //1.拿到子控件的x,y
        let x = view.frame.origin.x
        let y = view.frame.origin.y

        //2.进行减法,并且返回
        return CGPointMake(point.x - x, point.y - y)

    }  

Objective-C

  • 这里我的另一种思路,但是不提倡
/*只要进入了这个方法,那就代表了这个视图,是可以与用户交互,包含那个点的。
但是站在面向对象的角度,思考问题,”谁最清楚,控件能否被点击,
点在不在自己身上,当然是自己",所以不提倡这样的写法*/
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
   
    int count = (int)self.subviews.count;

    for( int i = count - 1 ; i >= 0 ; --i ) {

        //1.拿到子控件
        UIView * childView = self.subviews[i];

        //2.转换坐标点
        CGPoint childPoint = [self convertPoint:point toView:childView];

        //3.判断子控件能不能与用户交互
        BOOL flagEnable = childView.userInteractionEnabled == YES || childView.hidden == NO || childView.alpha > 0.01;

        //4.判断点在不在子控件上
        BOOL flagInside = [childView pointInside:childPoint withEvent:event];

        //5.如果都可以,那么继续递归
        if (flagInside && flagEnable) {

            UIView *firstView = [childView hitTest:childPoint withEvent:event];
            //6.如果有,就回传
            if (firstView) {
                return firstView;
            }
        }
    }

    //7.没找到最合适的就返回自己
    return self;
}

你可能感兴趣的:(iOS事件处理——Swift & Objective-C 表述)