在控制器中寫下如下代碼
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *layerView;//在Storyboard中拖入的視圖
@property (nonatomic, strong) CALayer *blueLayer;//此處一定要強引用,否則會被銷毀無法顯示
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.blueLayer = [CALayer layer];
self.blueLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
self.blueLayer.backgroundColor = [UIColor blueColor].CGColor;
//add it to our view
[self.layerView.layer addSublayer:self.blueLayer];
}
CALayer并不關(guān)心任何響應(yīng)鏈事件,所以不能直接處理觸摸事件或者手勢。但是它有一系列的方法幫你處理事件:-containsPoint:和-hitTest:。
-containsPoint:接受一個在本圖層坐標系下的CGPoint,如果這個點在圖層frame范圍內(nèi)就返回YES。使用-containsPoint:方法來判斷到底是白色還是藍色的圖層被觸摸了。這需要把觸摸坐標轉(zhuǎn)換成每個圖層坐標系下的坐標,結(jié)果很不方便。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//get touch position relative to main view
CGPoint point = [[touches anyObject] locationInView:self.view];
NSLog(@"%f,%f",point.x ,point.y);
//convert point to the white layer's coordinates
point = [self.layerView.layer convertPoint:point fromLayer:self.view.layer];
NSLog(@"-----%f,%f",point.x ,point.y);
//get layer using containsPoint:
if ([self.layerView.layer containsPoint:point]) {
//convert point to blueLayer’s coordinates
point = [self.blueLayer convertPoint:point fromLayer:self.layerView.layer];
NSLog(@"++++++%f,%f",point.x ,point.y);
if ([self.blueLayer containsPoint:point]) {
[[[UIAlertView alloc] initWithTitle:@"Inside Blue Layer"
message:nil
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil] show];
} else {
UIAlertController * alertView = [UIAlertController alertControllerWithTitle:@"Inside White Layer" message:nil preferredStyle:UIAlertControllerStyleAlert];
[alertView addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"成功了");
}]];
[self presentViewController:alertView animated:true completion:nil];
// [self performSelector:@selector(action) withObject:nil afterDelay:3];
}
}
}
-hitTest:方法同樣接受一個CGPoint類型參數(shù),而不是BOOL類型,它返回圖層本身,或者包含這個坐標點的葉子節(jié)點圖層。這意味著不再需要像使用-containsPoint:那樣,人工地在每個子圖層變換或者測試點擊的坐標。如果這個點在最外面圖層的范圍之外,則返回nil。具體使用-hitTest:方法被點擊圖層的代碼如下。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//get touch position
CGPoint point = [[touches anyObject] locationInView:self.view];
//get touched layer
CALayer *layer = [self.layerView.layer hitTest:point];
//get layer using hitTest
if (layer == self.blueLayer) {
[[[UIAlertView alloc] initWithTitle:@"Inside Blue Layer"
message:nil
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil] show];
} else if (layer == self.layerView.layer) {
[[[UIAlertView alloc] initWithTitle:@"Inside White Layer"
message:nil
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil] show];
}
}
注意當調(diào)用圖層的-hitTest:方法時,測算的順序嚴格依賴于圖層樹當中的圖層順序(和UIView處理事件類似)。之前提到的zPosition屬性可以明顯改變屏幕上圖層的順序,但不能改變事件傳遞的順序。
這意味著如果改變了圖層的z軸順序,你會發(fā)現(xiàn)將不能夠檢測到最前方的視圖點擊事件,這是因為被另一個圖層遮蓋住了,雖然它的zPosition值較小,但是在圖層樹中的順序靠前。