源码0306-hitText底层实现
事件是不是系统事件,是系统事件交给代理处理(比如程序启动完成时交给代理开启一个runRoop);
不是系统事件就交给主窗口处理(keyWindow);
主窗口会在视图中找到最合适的视图来处理触摸事件;
事件传递的过程-事件处理的过程(谁能处理)----
// XMGWindow.m // 04-事件的产生和传递 #import "XMGWindow.h" @implementation XMGWindow // 事件传递的时候调用 // 什么时候调用:当事件传递给控件的时候,就会调用控件的这个方法,去寻找最合适的view // 作用:寻找最合适的view // point:当前的触摸点,point这个点的坐标系就是方法调用者 //- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event //{ // // 调用系统的做法去寻找最合适的view,返回最合适的view // UIView *fitView = [super hitTest:point withEvent:event]; // //// NSLog(@"fitView--%@",fitView); // return fitView; //} // 作用:判断当前这个点在不在方法调用者(控件)上 //- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event //{ // return YES; //} //- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event //{ //// NSLog(@"%s",__func__); //} // 点击黄色视图 -》 事件 -》 UIApplication -> UIWindow // 因为所有的视图类都是继承BaseView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // 1.判断当前控件能否接收事件 if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil; // 2. 判断点在不在当前控件 if ([self pointInside:point withEvent:event] == NO) return nil; // 3.从后往前遍历自己的子控件 NSInteger count = self.subviews.count; for (NSInteger i = count - 1; i >= 0; i--) { UIView *childView = self.subviews[i]; // 把当前控件上的坐标系转换成子控件上的坐标系 CGPoint childP = [self convertPoint:point toView:childView]; UIView *fitView = [childView hitTest:childP withEvent:event]; if (fitView) { // 寻找到最合适的view return fitView; } } // 循环结束,表示没有比自己更合适的view return self; } @end
// BaseView.m // 04-事件的产生和传递 #import "BaseView.h" @implementation BaseView - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"%@---touchesBegan",[self class]); } // UIApplication -> [UIWindow hitTest:withEvent:] -> whiteView hitTest:withEvent // 因为所有的视图类都是继承BaseView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // NSLog(@"%@--hitTest",[self class]); // return [super hitTest:point withEvent:event]; // 1.判断当前控件能否接收事件 if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil; // 2. 判断点在不在当前控件 if ([self pointInside:point withEvent:event] == NO) return nil; // 3.从后往前遍历自己的子控件 NSInteger count = self.subviews.count; for (NSInteger i = count - 1; i >= 0; i--) { UIView *childView = self.subviews[i]; // 把当前控件上的坐标系转换成子控件上的坐标系 CGPoint childP = [self convertPoint:point toView:childView]; UIView *fitView = [childView hitTest:childP withEvent:event]; if (fitView) { // 寻找到最合适的view return fitView; } } // 循环结束,表示没有比自己更合适的view return self; } @end
07-hitText练习1
当从storyboard往类里面拖线的时候发现不能拖,可以反过来从 类文件(xxx.m)拖到storyboard中;
// YellowView.m // 07-hitText练习1 #import "YellowView.h" @interface YellowView () @property (nonatomic, weak) IBOutlet UIButton *btn; @end @implementation YellowView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // 当前坐标系上的点转换到按钮上的点 CGPoint btnP = [self convertPoint:point toView:self.btn]; // 判断点在不在按钮上 if ([self.btn pointInside:btnP withEvent:event]) { // 点在按钮上 return self.btn; }else{ return [super hitTest:point withEvent:event]; } } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"%@",self.btn); NSLog(@"%s",__func__); } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end
08-hitText练习2
// ViewController.m // 08-hitText练习2 #import "ViewController.h" #import "PopBtn.h" @interface ViewController () @end @implementation ViewController - (IBAction)popChatView:(PopBtn *)sender { // 弹出对话框 UIButton *chatView = [UIButton buttonWithType:UIButtonTypeCustom]; chatView.bounds = CGRectMake(0, 0, 200, 200); chatView.center = CGPointMake(100, -100); [chatView setBackgroundImage:[UIImage imageNamed:@"对话框"] forState:UIControlStateNormal]; [chatView setBackgroundImage:[UIImage imageNamed:@"小孩"] forState:UIControlStateHighlighted]; sender.chatView = chatView; [sender addSubview:chatView]; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
// PopBtn.h // 08-hitText练习2 #import <UIKit/UIKit.h> @interface PopBtn : UIButton @property (nonatomic, weak) UIButton *chatView; @end
// PopBtn.m // 08-hitText练习2 #import "PopBtn.h" @implementation PopBtn - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // 当前控件上的点转换到chatView上 CGPoint chatP = [self convertPoint:point toView:self.chatView]; // 判断下点在不在chatView上 if ([self.chatView pointInside:chatP withEvent:event]) { return self.chatView; }else{ return [super hitTest:point withEvent:event]; } } //找到合适的事件处理对象,来处理事件; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { // 获取UITouch UITouch *touch = [touches anyObject]; // 获取当前的点 CGPoint curP = [touch locationInView:self]; // 获取上一个的点 CGPoint preP = [touch previousLocationInView:self]; // 获取偏移量 CGFloat offsetX = curP.x - preP.x; CGFloat OffsetY = curP.y - preP.y; // 修改控件的位置 CGPoint center = self.center; center.x += offsetX; center.y += OffsetY; self.center = center; } @end
本人无商业用途,仅仅是学习做个笔记,特别鸣谢小马哥,学习了IOS,另日语学习内容有需要文本和音频请关注公众号:riyuxuexishuji