1. 程式人生 > >iOS 【UIKit-事件產生與傳送 練習(重寫hitTest和pointInside方法)】

iOS 【UIKit-事件產生與傳送 練習(重寫hitTest和pointInside方法)】

練習要求:

在下圖中點選到綠色Button區域,Button響應(包括YellowView覆蓋的綠色Button部分也是由綠色Button來響應)。點選YellowView部分(除覆蓋綠色Button外的),YellowView響應。

解決思路:

如果我們只是一味的和之前一樣重寫綠色Button的hitTest方法,是不能很好的區分YellowView與綠色Button的重合部分的,他會讓點選的所有地方都是由綠色Button來響應。顯然和我們的想法有了偏離。

那麼我們應該在hitTest方法(YellowView中的hitTest方法)的重寫中判斷一下,如果點恰好也在綠色Button上,那麼我們就可以讓YellowView不響應這個事件,那麼編譯器就會接著往下遍歷綠色Button,然後讓綠色Button去響應。當然這裡重寫的hitTest方法是重寫YellowView中的,多體會幾次就可以理解了。

程式碼:

#import "YellowView.h"

@implementation YellowView

// 輸出響應者
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"%s",__func__);
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    // 將point轉化成為Button座標系上的點
    CGPoint buttonPoint = [self convertPoint:point toView:_button];
    
    // 如果點在綠色Button上,那麼返回nil,也就是YellowView退出遍歷了,不讓YellowView作為響應者
    if ([_button pointInside:buttonPoint withEvent:event]) {
        return nil;
    }
    
    // 當然如果點不在綠色Button上,那麼就接著原來的hitTest方法執行,執行super語句。
    return [super hitTest:point withEvent:event];
}

@end

當然除了重寫hitTest方法可以實現這個功能,我們也可以重寫pointInside方法。

程式碼:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    // 這裡的呼叫者是self,因為point是當前view中的點
    CGPoint buttonPoint = [self convertPoint:point toView:_button];
    
    // 需要注意這裡的呼叫者是_button,因為這裡的point是buttonPoint也就是綠色Button中的點
    if ([_button pointInside:buttonPoint withEvent:event]) {
        return nil;
    }
    
    return [super pointInside:point withEvent:event];
}

只需要將上面重寫hitTest方法的地方替換下來就好了。原理都是一樣的。