IOS 开发 手势使用

来源:互联网 发布:年轻员工管理知乎 编辑:程序博客网 时间:2024/05/24 06:06

首先为了防止看我的博客的人刚打开就关闭,所以就先给个手势的例子

[objc] view plain copy 在CODE上查看代码片派生到我的代码片
  1. UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapView:)];  
  2. tapGesture.numberOfTapsRequired = 1;  
  3. tapGesture.numberOfTouchesRequired = 1;  
  4. [self.view addGestureRecognizer:tapGesture];  

话说回来,如果直接讲例子以及如何使用函数,没多大意思,而且这种东西就成了记单词,不好不好实在不好,了解下机理,那就不用背单词了,不论怎样变都无所谓了。上个博客讲了事件的传播途径和顺序。那么本次就说说如何在这样的大前提下,做些设置来适应特殊的需求

首先来讲一下手势的识别和touch事件和处理手势的target之间的关系。如下图:



当用户触摸屏幕,会有touchbegin 事件,然后触摸也可以移动,也会有touchmove,然后离开就会有touchend事件,总的来说touch事件有一下三个阶段:


首先touchbegin ,之后用户移动的的话会进入touchmove,然后手指离开就会有touchend,用户也可以直接离开,就直接冲touchbegin 到tauchend。无论哪个阶段,ios都会将这些阶段包裹成一个touch事件,先传给手势们,手势会分析这些事件,改变自己的状态,然后发送消息给target,target就会调用处理函数进行事件处理。什么是手势状态改变。看下图



这个图是手势的状态迁移自动机,左边是不连续的单一手势,右边是连续的手势。
手势刚开始默认处于possible状态,当分析出可以识别时,单一分离手势立马变为recognized状态,并发送消息给target,不识别就变为Failed,但不发消息给target。
连续的手势,当初次识别时,其从possible变为begin状态,然后发送消息给target,然后继续分析touch事件,然后处于change,发送消息给target,当变化后不符合该手势的模式时,就变为canceled状态,但不发送消息给target,如果touch end事件来了后,就变为recognized,并发送消息给target。
总之在状态变化的时候会发送消息给target,但变化的目标状态是 canceled 或者 failed的话,是不发送消息给target的。还有当处于recognized(end)状态是,ios会把手势的状态重新置为possible状态,但不发消息给target。
讲了这么多下来就讲如何满足特定需求。先看一下两个手势的代理函数

 iOS是如何让手势处理touch事件的
我们之前说过,事件一旦被某个手势拦截,就不会再传递,其实这只是表象,iOS内在的机理是这样的,touch事件每次会按照不同的顺序传递给手势,IOS在发给手势的时候先会查找各个手势的代理函数和属性来确认是否要发送事件给这个手势,对每个手势发送完成后,每个手势会根据自己的代理函数和属性来改变自己的状态,然后当出现有手势们的状态改变信号的时候,IOS会询问代理及属性,哪个手势该发送消息给它的target。下图是整个IOS事件传递和处理详细流程。
        1.touch事件传递给手势时首先询问 gestureRecognizer:shouldReceiveTouch: 这个代理函数返回YES,则手势就会受到这个touch事件,也就是说这个代理函数是来确定这个手势是否能看的见这个事件,如果返回NO,什么情况呢,那就是手势自己原来是什么状态压根不变。
            2. 如果1中的代理函数返回为YES,手势开始识别,进入改变状态判断阶段, 那么手势会根据事件改变自己的状态,但是出了本身的手势的原则外,还有什么,代理和属性。gestureRecognizerShouldBegin:如果这个代理函数返回NO,那么就该手势状态就变为Failed。返回YES,就根据他自己手势定值的规则改变自己的状态。
   3.改变完状态后,如果手势中有手势的状态为End(Recognized),也就是识别状态,这个时候系统要根据代理决定那个手势可以发送识别消息给target,访问的代理函数如下
    (1),首先访问

- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer 

- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer

这两个函数是类方法,返回值为BOOL,canPreventGestureRecognizer,这个函数返回YES就说明这个手势可以在和其他的手势在一起出现recognized状态的时候,其他手势不能向其target发布识别消息。canBePreventGestureRecognizer刚好相反。然后这两个被访问后,得到的结果不是最后结果。还要继续访问其他的代理函数,如果其他的代理函数允许他们一起响应,那么他们也是会一起响应的,比如(2)中

    (2),再访问

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer

这个函数也返回YES,就表明两个手势可以同时触发,不过这个函数在两个手势之间会被调用两次,但参数顺序会变,只要有个次返回YES,那么就表明这两个手势可以同时识别。这个就是区别于(1)中的两个函数,他们是单向的。

    (3)[A requireGestureRecognizerToFail:B];(1),(2)完成后会查看这个依赖,三部完成后,决定那个手势该发给其代理函数消息。

gestureRecognizerShouldBegin:gestureRecognizer:shouldReceiveTouch是当iOS访问在传递touch事件之前会询问手势的代理,问是否要传递touch事件给这个手势。默认为YES,表明是传,为NO的话,表明是不传,不传就表明手势的状态是不可能发生改变的,也就是说手势就当什么也没发生过。


手势的几个属性

 (1)cancelsTouchesInView这给属性是默认为YES,其是当手势被识别的时候,是否取消touch事件传递给手势所关联的view

 (2)delaysTouchesBegan默认为NO,这个属性的作用是,当手势在分析touchbegin,和touch move时,但是手势还没有分分析出来是识别还是不识别,也就是手势的状态为possible状态,当这个属性为YES,那么系统会先挂起(不丢去)touch事件,然后继续当手势识别失败了,系统会将失败之前的touch事件全部传递给view。当为NO时,就是实时的每一次view都会收到touch事件,但除了touchend外。

 (3)delaysTouchesEnded默认为YES,当其为YES时在手势在UITouchPhaseEnded阶段,当手势识别成功了后,view就是收到touch canceled的事件,失败后会收到touched,当其为NO,手势在分析end消息时,view就受到了这个消息。

总结,有事件的传输路径和次序,已经由ios规定好了,那么以上的方法也就是在这个基础上做的,有的事在将要通知手势发生了touch事件前,有的事之后。总之,分析手势的时候一定时时刻刻想到touch事件的传播。

好了手势的使用基本上将的差不多了,希望大家能多提意见

0 0