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;
}
發佈了26 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章