咱們在有多個 UIView 層疊時,好比一個按鈕被一個 UIView 遮蓋時,想要在點擊最上層的 UIView 時能觸發按鈕的相應事件,咱們該如何實現呢,初步能夠想到幾種辦法:html
1. 把按鈕上層的全部 UIView 的 userInteractionEnabled 屬性設置爲 NO,要是 UIView 有本身的交互事件該如何辦呢?並且這個 userInteractionEnabled 不能動態設置,等到點擊後決定設置它的 NO 是沒用的git
2. UIView 接受到點擊事件後主動去觸發下面按鈕的點擊,這時的關題有三,按鈕沒有點擊過程當中的交換效果、多層 UIView 時不切實際,逐層下傳嗎、還有就是其餘雙擊、三擊或別的手勢如何處理github
我也一直被前面兩種方式糾纏着,同時也讓 UIPopoverController 的 NSArray *passthroughViews 屬性提醒着,由於對於 UIPopoverController,設置到它的 passthoughViews 屬性中的控件事件能夠徹底從 UIDimmingView 下透出來。但苦於不可能看到 UIPopoverController 的源碼,仍是後面一而再的 Google 終於發現了 UIView 的方法:ide
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
只要實現了最頂層的 UIView 的 hitTest 方法,在某些狀況返回下層的某個按鈕實例,即至關於把那個按鈕的事件透出來了,好比在點擊落在該按鈕上時,無論這個按鈕在 UIView 下多少層均可以把它挖出來。this
關鍵要理解 hitTest 方法的做用,可參考:atom
1.http://blog.sina.com.cn/s/blog_677089db01012wpg.html
2. https://github.com/werner77/WEPopoverspa
有兩部分代碼,分別是 ViewController 和 CustomController.net
// // ViewController.h // // Created by Unmi on 11/15/11. // Copyright (c) 2011 http://unmi.cc. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController{ } @end // // ViewController.m // // Created by Unmi on 11/15/11. // Copyright (c) 2011 http://unmi.cc. All rights reserved. // #import "ViewController.h" #import "CustomView.h" @implementation ViewController{ UIButton *passthroughButton; } #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; passthroughButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [passthroughButton setTitle:@"Passthrough" forState:UIControlStateNormal]; [self.view addSubview:passthroughButton]; passthroughButton.frame = CGRectMake(20, 50, 120, 28); [passthroughButton release]; CustomView *customView = [[CustomView alloc] initWithFrame:CGRectMake(80, 10, 300, 200)]; customView.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:.5]; customView.passthroughViews = [NSArray arrayWithObject:passthroughButton]; [self.view addSubview:customView]; [customView release]; } - (void)dealloc { [super dealloc]; }@end
// // CustomView.h // TestPopover // // Created by Unmi on 2/19/12. // Copyright (c) 2012 http://unmi.cc. All rights reserved. // #import <UIKit/UIKit.h> @interface CustomView : UIView @property (nonatomic, copy) NSArray *passthroughViews;@end // // CustomView.m // // Created by Unmi on 2/19/12. // Copyright (c) 2012 http://unmi.cc. All rights reserved. // #import "CustomView.h" @interface CustomView() -(BOOL) isPassthroughView: (UIView*) view;@end @implementation CustomView{ BOOL testHits; } @synthesize passthroughViews=_passthroughViews; -(UIView*) hitTest:(CGPoint)point withEvent:(UIEvent *)event{ if(testHits){ return nil; } if(!self.passthroughViews || (self.passthroughViews && self.passthroughViews.count == 0)){ return self; } else { UIView *hitView = [super hitTest:point withEvent:event]; if (hitView == self) { //Test whether any of the passthrough views would handle this touch testHits = YES; CGPoint superPoint = [self.superview convertPoint:point fromView:self]; UIView *superHitView = [self.superview hitTest:superPoint withEvent:event]; testHits = NO; if ([self isPassthroughView:superHitView]) { hitView = superHitView; } } return hitView; } } - (BOOL)isPassthroughView:(UIView *)view { if (view == nil) { return NO; } if ([self.passthroughViews containsObject:view]) { return YES; } return [self isPassthroughView:view.superview]; } -(void) dealloc{ self.passthroughViews = nil; } @end