ios 超出父控制元件區域支援點選事件
標題中的需求其實常常能遇到,如下圖
圖 1
當按鈕超出Tab bar的view後,那麼其實按鈕超出的部分是無法被點選的。那麼先來說說解決辦法
1.我們重寫藍色view的- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event的方法
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{ //if內的條件應該為,當觸控點point超出藍色部分,但在黃色部分時 if (.....){ return YES; } return NO; }
那麼以上為什麼能解決方法?
這和iOS的事件分發機制 hit-Testing有關,簡單的說,hit-Testing的作用就是找出你每次觸控式螢幕幕,點到的究竟是哪個view。
比如以下這個圖
圖 2
當我去點選View-C的時候,hit-Testing實際上是這樣檢測的
1.首先,檢視會先從View-A開始檢查,發現觸控點在View-A,所以檢查View-A的子檢視View-B。
2.發現觸控點在View-B內,好棒!看看View-B內的子檢視View-C。
3.發現觸控點在View-C內,但View-C沒有子檢視了,所以View-C是此次觸控事件的hit-TestView了。
那麼UIView中其實提供了兩個方法來確定hit-TestView
1.- (UIView )hitTest:(CGPoint)point withEvent:(UIEvent
2.- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;//這個就是我們上面重寫的方法
注意其實在每次遞迴去呼叫hitTest:(CGPoint)point withEvent:(UIEvent *)event之前,都會呼叫pointInside:withEvent:來確定該觸控點是否在該View內。
所以當我們重寫pointInside:(CGPoint)point withEvent:(UIEvent *)event後,其實我們的點選後呼叫hitTest來遞迴的找hit-TestView的區域從這樣:
圖 3
變成了這樣:
圖 4
這樣當我們愉快的點選上半凸起的區域時,hit-Testing便回去檢查藍色檢視內的子檢視,即黃色區域。從而來完成此次觸控事件。
Enjoy :)
2017年3月1日更新
針對gwk_ios提問,我首先表示感謝,我們有必要把這個問題拿出來,研究一下。
讓我們先看個圖:
圖 5
恩,這圖似乎有點大。不過沒事。
gwk_iost提出了2個問題
如果- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 方法只要return yes 就能點選超出父view邊界的子view上的button呢
這樣做實際上會有一個問題,如上圖,如果在View A中,先新增View B(包含了Button A),再新增Button B,那麼再點選Button B時,Button B的方法會被正確觸發。
但是,[如果在View A中,先新增Button B,再新增View B(包含了Button A)],這個時候,你會發現,點選Button B時,方法無法被正確觸發了。因為你在點選View A內的任意位置時,系統會優先呼叫View B 的pointInSide: WithEvent:方法,這時候你返回YES,就截斷了事件,包括點選Button B。
那麼 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 內if判斷該怎麼寫呢
其實point會返回的座標是基於該View的座標系(所以超出該View時,可能會出現負數),以iphone 7的螢幕大小為例子:
圖 6
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
if (CGRectContainsPoint(CGRectMake(0, 0, 87.5, 100),point)||CGRectContainsPoint(CGRectMake(87.5, -100, 200, 200), point)||CGRectContainsPoint(CGRectMake(287.5, 0, 87.5, 100),point)) {
return YES;
}
return NO;
}
Enjoy :)