textField不能响应-事件的传递与响应

来源:互联网 发布:淘宝装修好的怎么备份 编辑:程序博客网 时间:2024/05/14 08:32

最近在写项目的过程中遇到了一个问题:我在UIView上加了一个ImageView,然后在ImageView上加了一个userName 的TextField框,最后在运行的时候发现文本框无法响应,即使在代理方法里面设置了 [self.userName becomeFirstResponser]也无济于事,然后一个学长告诉我加上imagev.userInteractionEnabled=YES;结果真的好了,是事件传递和响应的问题,抱着求知的心态,通过在网上查资料和看技术博客,对事件的传递和响应有了自己的理解,就想以博客的形式记录下来,对于哪里理解的不正确或者有偏差,欢迎大家批评指正,下面就是我的一些理解

注:下面以触摸事件为例

当发生一次触摸事件的时候,系统就会把这个事件添加到由UIApplication管理的一个队列里面(之所以使用队列而不是栈是因为,队列是先进先出的,符合先发生的事件先处理的认识)

* 第一步:事件的传递

* 总体概括:

UIApplication从队列的队头取出一个事件,分发给应用程序的主窗口(keyWindow),keyWindow在视图的体系结结构了找到最合适色视图来处理这个事件,即hit-test view,找到之后,就会调用视图控件的touch系列方法来处理事件

* 事件传递的详细步骤(从父控件到子控件)

1.UIApplication从队列中取出一个事件,法从给keyWinndow(窗口),如果是系统事件,则发送给单例。

2.keyWindow接受到事件以后调用

//该方法针对于控件而言
-(UIView )hitTest:(CGPoint)point withEvent:(UIEvent )event{

1. 判断控件能否传递事件  if(控件不可以传递事件){  return nil;  }

对于第1步返回的 nil 注意:但是系统自带的窗口肯定是可以传递事件的,针对于用户自定义的window,如果用户自定义的window里面设置window不可见,那么就会返回nil,当window返回nil,就意味着没有控件能处理事件

2. (断触摸点是否在当前控件)//这个判断是hitTest方法底层调用该方法底层调用-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event){} if (不在当前控件上){ return nil; }

对于第2步里面的 nil 注意:说明当前控件不是最合适的view,返回nil,同样如果是window里面返回的nil,说明没有控件能处理该事件,如果是其他控件,说明该控件不能处理,那么当返回一个nil的时候,父控件接收到消息,就会返回本身,说明没有比自己更合适的控件能作为最合适view

3. 从后往前遍历该控件的所有子控件

对于第3步要注意:这里多了一步,这里在在判断子控件的触摸点问题时,需要用[self convertPoint:toView:子控件]方法将当前控件的坐标系转成子控件的坐标系,传入检查触摸点在不在子控件身上的方法,将坐标系转成本身坐标系的原因是为了好判断,只要通过判断触摸点的横坐标有没有超过子控件的宽度,即可以判断触摸点是否在子控件上

}

注意:不能传递事件:

  • 不允许交互:userInteractionEnabled = NO(UIImageView默认是NO),
    enable = NO(UIButton默认是YES);
  • 隐藏:如果把父控件隐藏,那么子控件也会隐藏,隐藏的控件不能接受事件
  • 透明度:当透明度0时

第二步:事件的响应

经过第一步我们找到了随时和处理事件的控件,这个控件有优先处理事件的权利,但是不一定会处理,只有当重写了UIResponder类里面的

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

才可以,该默认是把事件顺着响应者链往上抛,(如果view是当前Controller上的view,那么父控件就是当前Controller,不然就是他的父控件),这样一直往上抛, 直到找到重写了touchBegan方法的响应者对象,该事件就会被处理,如果我们没有人为在处理完事件之后添加

[super touchesBegan:touches withEvent:event]

那么事件处理完就结束,不会再传递给下一个响应者,但是如 果加上了,就算事件已经处理过,父控件还是会处理再一次事件,这个性能可以用于让多个对象处理一个事件,而且我们只需要在
touchbegin里面这样写,其他touch系列方法会响应

Touch系列方法要点

* 当一个手指触摸的时候,touchbegan会创建一个UITouch对象* 当两个手指一前一后触摸的时候,touchbegan方法会调用两次,产生两个UITouch对象*当两个手指同时触摸的时候,touchbegan调用一次,产生两个UITouch的对象  

注意:

* 1:UIButton里面的

button addTarget:self action:@selector(button action)            forControlEvents:UIContnolEventTouchUpInside]

其实就是对touch系列方法的封装,所以 如果我们实现了这个方法,也就是重写了touch系列方法
* 2:因为 UIView以及UIViewController都继承于UIResponser,所以我们如果要重写UIView的touch系列方法,就要自定义一个view,如果写在Controller里面。那么就是Controller的touch系列方法
* 3: 如果当事件传递到了UIAPPlication还没有处理,那么UIApplication就会处理,如果UIApplication也不处理,那 么这个事件就会被废弃

看完这个我对于自己一开始遇到的问题有了答案,因为ImageView的默认交互是NO,所以事件在传递的过程中,遇到了ImageView,发现他不能传递,hitTest:withEvent方法就返回了self.view,所以我的文本框并没有加入到响应链里面,所以不能够对事件作出响应

2 0
原创粉丝点击