资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

ios开发

IOS学习可以先从基础开始,以后会介绍写内容吧

为回民等地区用户提供了全套网页设计制作服务,及回民网站建设行业解决方案。主营业务为成都网站建设、做网站、回民网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!

这篇文章想跟大家分享的主旨是iOS捕获用户事件的各种情况,以及内部封装的一些特殊事件。

我们先从UIButton谈起,UIButton大家使用的太多了,他特殊的地方就在于其内置的普通Default/高亮Highlighted/选择Selected/可用Enable的几个状态(UIControlState)。其次就是SDK内部已经为我们封装了以下用户事件:

ios 开发

那么他看起来并不像N叉树,但是不代表者不是一颗N叉树,当我们项目复杂之后,这个View可不可以有多个UIButton节点?所以他就是一棵树。

实际上我们要把这棵树写完整,应该还要算上UIButton的UILabel和UIImageView,因为他们也是UIReponder的子类。这里先不考虑了。

我们对UIButton来讲,他此时若是叶节点,那么这时我们针对他所在的响应链来说,他在他之前的响应者就应该是我们controller的view(树中的叶节点比父节点永远更优先被分发事件,但是并不是说他就能在时间上先响应,我们下面讲为什么)。所以我们尝试在任意地方打印这个Button的nextReponder对象。nextResponder对象是UIReponder类的实例方法,它会返回任意对象在树中的上一个响应者实例:

[cpp]viewplaincopyprint?
  1. NSLog(@"%@",_testButton.nextResponder);

NSLog(@"%@",_testButton.nextResponder);

控制台输出消息:

2013-09-2103:40:25.989响应链[614:60b]>


我们可以根据这个UIView的尺寸来得知,他就是我们唯一的控制器中的那个UIView。

接下来我们再打印下这个UIView的下一个响应者是谁:

[cpp]viewplaincopyprint?
  1. NSLog(@"%@",_testButton.nextResponder.nextResponder);

NSLog(@"%@",_testButton.nextResponder.nextResponder);

输出:

2013-09-2103:45:03.914响应链[621:60b]

依次看,接着加一个nextResponder:

2013-09-2103:50:49.428响应链[669:60b](null)

为什么这里ViewController没有父亲呢?

注意这句代码我是写在ViewDidLoad中,而我们知道这个方法的生命周期比较早,所以我们换个地方写或者延迟一段时间再打印,两种方法都可以得到结果(由此可以推理出我们响应者树的构造过程是在ViewDidLoad周期中来完成的,这个函数会将当前实例的构成的响应者子树合并到我们整个根树中):

2013-09-2103:53:47.304响应链[681:60b];layer=>

再继续往上追朔:

[cpp]viewplaincopyprint?
  1. doubledelayInSeconds=2.0;

  2. dispatch_time_tpopTime=dispatch_time(DISPATCH_TIME_NOW,(int64_t)(delayInSeconds*NSEC_PER_SEC));

  3. dispatch_after(popTime,dispatch_get_main_queue(),^(void){

  4. NSLog(@"%@",_testButton.nextResponder.nextResponder.nextResponder.nextResponder);

  5. });

 double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
         NSLog(@"%@",_testButton.nextResponder.nextResponder.nextResponder.nextResponder);
    });
   

2013-09-2103:56:22.043响应链[690:60b]

再加一个:

2013-09-2103:56:51.186响应链[696:60b]

那么我们的appDelegate还有没有父节点?

2013-09-2103:57:22.588响应链[706:60b](null)

没有了,注意,一个从叶节点开始分发的事件,最多也就只能分发到我们的AppDelegate了!

这个树形结构在我们的项目中尤为重要,举个栗子,如果我们想在一个view中重写UITouchEvent的4个方法,并且不影响他的父视图也响应这些事件,就要注意你重写的方式了,比如我们在ViewController中重写touchBegan如下:

[cpp]viewplaincopyprint?
  1. -(void)touchesBegan:(NSSet*)toucheswithEvent:(UIEvent*)event

  2. {

  3. NSLog(@"ViewController接收到触摸事件");

  4. }

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"ViewController接收到触摸事件");
}

在appDelegate的中同样也写上这一段:

[cpp]viewplaincopyprint?
  1. -(void)touchesBegan:(NSSet*)toucheswithEvent:(UIEvent*)event

  2. {

  3. NSLog(@"appDelegate接收到触摸事件");

  4. }

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"appDelegate接收到触摸事件");
}


那么究竟是谁被触发呢?

2013-09-2104:02:49.405响应链[743:60b]ViewController接收到触摸事件

这个很好理解,我刚刚也说了,viewController明显是appDelegate的子节点,他有事件分发的优先权。如果我们想两个地方都触发呢?这里super一下就可以了:

[cpp]viewplaincopyprint?
  1. -(void)touchesBegan:(NSSet*)toucheswithEvent:(UIEvent*)event

  2. {

  3. [supertouchesBegan:toucheswithEvent:event];

  4. NSLog(@"ViewController接收到触摸事件");

  5. }

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    NSLog(@"ViewController接收到触摸事件");
}
输出:

2013-09-2104:07:26.206响应链[749:60b]appDelegate接收到触摸事件

2013-09-2104:07:26.208响应链[749:60b]ViewController接收到触摸事件

注意看时间戳,appDelegate虽然优先级别不如ViewController,但是他响应的时间上面足足比ViewController早了0.002秒,我这里试了几次,都是相差0.002秒。

那么我们分析一下这里的响应者链是怎样工作的:

用户手指触摸到了UIView上,由于我们没有重写UIView的UITouchEvent,所以他里面和super执行的一样的,将该事件继续分发到UIViewController;

UIViewController的TouchBegan被我们重写了,如果我们不super,那么我们在这里写响应代码。事件到这里就不继续分发了。可想而知,UIViewController祖先节点:UIWindow,UIApplication,AppDelegate都无权被分发此事件。

如果我们super了TouchBegan,那么此次触摸事件由

ViewController分发给UIWindow,

UIWindow继而分发给UIApplication,

UIApplication再分发给AppDelegate,

于是我们在ViewController和appDelegate的touchBegan方法中都捕获到了这次事件。

到这里大家应该对这个响应者树有一个很好的理解了吧?

接下来我们再谈谈第一响应者,和UIButton上的事件分发。


网站名称:ios开发
文章URL:http://cdkjz.cn/article/gcidig.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220