美文网首页
iOS触摸事件处理

iOS触摸事件处理

作者: 醉叶惜秋 | 来源:发表于2016-05-12 21:59 被阅读120次

iOS触摸事件处理

主要是记录下iOS的界面触摸事件处理机制,然后用一个实例来说明下应用场景.
一、处理机制
界面响应消息机制分两块,(1)首先在视图的层次结构里找到能响应消息的那个视图。(2)然后在找到的视图里处理消息。
【关键】(1)的过程是从父View到子View查找,而(2)是从找到的那个子View往父View回溯(不一定会往回传递消息)。

1.1、寻找响应消息视图的过程可以借用M了个J的一张图来说明。



处理原理如下:
• 当用户点击屏幕时,会产生一个触摸事件,系统会将该事件加入到一个由UIApplication管理的事件队列中
• UIApplication会从事件队列中取出最前面的事件进行分发以便处理,通常,先发送事件给应用程序的主窗口(UIWindow)
• 主窗口会调用hitTest:withEvent:方法在视图(UIView)层次结构中找到一个最合适的UIView来处理触摸事件
(hitTest:withEvent:其实是UIView的一个方法,UIWindow继承自UIView,因此主窗口UIWindow也是属于视图的一种)
• hitTest:withEvent:方法大致处理流程是这样的:
首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内:
▶ 若pointInside:withEvent:方法返回NO,说明触摸点不在当前视图内,则当前视图的hitTest:withEvent:返回nil
▶ 若pointInside:withEvent:方法返回YES,说明触摸点在当前视图内,则遍历当前视图的所有子视图(subviews),调用子视图的hitTest:withEvent:方法重复前面的步骤,子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图的hitTest:withEvent:方法返回非空对象或者全部子视图遍历完毕:
▷ 若第一次有子视图的hitTest:withEvent:方法返回非空对象,则当前视图的hitTest:withEvent:方法就返回此对象,处理结束
▷ 若所有子视图的hitTest:withEvent:方法都返回nil,则当前视图的hitTest:withEvent:方法返回当前视图自身(self)
• 最终,这个触摸事件交给主窗口的hitTest:withEvent:方法返回的视图对象去处理。
拿到这个UIView后,就调用该UIView的touches系列方法。
1.2、消息处理过程,在找到的那个视图里处理,处理完后根据需要,利用响应链nextResponder可将消息往下一个响应者传递。
UIAppliactionDelegate <- UIWindow <- UIViewController <- UIView <- UIView
【关键】:要理解的有三点:1、iOS判断哪个界面能接受消息是从View层级结构的父View向子View传递,即树状结构的根节点向叶子节点递归传递。2、hitTest和pointInside成对,且hitTest会调用pointInside。3、iOS的消息处理是,当消息被人处理后默认不再向父层传递。

二、应用实例
【需求】是:界面如下,
Window
  -ViewA
    -ButtonA
    -ViewB
      -ButtonB
层次结构:ViewB完全盖住了ButtonA,ButtonB在ViewB上,现在需要实现1)ButtonA和ButtonB都能响应消息 2)ViewA也能收到ViewB所收到的touches消息 3)不让ViewB(ButtonB)收到消息。
(首先解析下,默认情况下,点击了ButtonB的区域,iOS消息处理过程。
-ViewA
  -ButtonA
  -ViewB
    -ButtonB
当点击ButtonB区域后,处理过程:从ViewA开始依次调用hitTest
pointInside的值依次为:
ViewA:NO;
ViewB:YES;
ButtonB:YES;
ButtonB的subViews:NO;
所以ButtonB的subViews的hitTest都返回nil,于是返回的处理对象是ButtonB自己。接下去开始处理touches系列方法,这里是调用ButtonB绑定的方法。处理完后消息就停止,整个过程结束。)
【分析】:
实现的方式多种,这里将两个需求拆解开来实现,因为实现2就可以满足1。
2.1、需求1的实现,ViewB盖住了ButtonA,所以默认情况下ButtonA收不到消息,但是在消息机制里寻找消息响应是从父View开始,所以我们可以在ViewA的hitTest方法里做判断,若touch point是在ButtonA上,则将ButtonA作为消息处理对象返回。
代码如下:

pragma mark - hitTest

  • (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
    // 当touch point是在_btn上,则hitTest返回_btn
    CGPoint btnPointInA = [_btn convertPoint:point fromView:self];
    if ([_btn pointInside:btnPointInA withEvent:event]) {
    return _btn;
    }

    // 否则,返回默认处理
    return [super hitTest:point withEvent:event];

}

pragma mark - hitTest

  • (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
    // 当touch point是在_btn上,则hitTest返回_btn
    CGPoint btnPointInA = [_btn convertPoint:point fromView:self];
    if ([_btn pointInside:btnPointInA withEvent:event]) {
    return _btn;
    }

    // 否则,返回默认处理
    return [super hitTest:point withEvent:event];

}

pragma mark - hitTest

  • (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

{

// 当touch point是在_btn上,则hitTest返回_btn

CGPoint btnPointInA = [_btn convertPoint:point fromView:
self
];

if
([_btn pointInside:btnPointInA withEvent:event]) {

return
_btn;

}

// 否则,返回默认处理

return
[
super
hitTest:point withEvent:event];

}

这样,当触碰点是在ButtonA上时,则touch消息就被拦截在ViewA上,ViewB就收不到了。然后ButtonA就收到touch消息,会触发onClick方法。
2.2、需求2的实现,上面说到响应链,ViewB只要override掉touches系列的方法,然后在自己处理完后,将消息传递给下一个响应者(即父View即ViewA)。
代码如下:在ViewB代码里

  • (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
    NSLog(@"B - touchesBeagan..");

    // 把事件传递下去给父View或包含他的ViewController
    [self.nextResponder touchesBegan:touches withEvent:event];
    }

  • (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
    {
    NSLog(@"B - touchesCancelled..");
    // 把事件传递下去给父View或包含他的ViewController
    [self.nextResponder touchesBegan:touches withEvent:event];
    }

  • (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
    NSLog(@"B - touchesEnded..");
    // 把事件传递下去给父View或包含他的ViewController
    [self.nextResponder touchesBegan:touches withEvent:event];
    }

  • (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
    NSLog(@"B - touchesMoved..");
    // 把事件传递下去给父View或包含他的ViewController
    [self.nextResponder touchesBegan:touches withEvent:event];

}

pragma mark - touches

  • (
    void
    )touchesBegan:(
    NSSet
    *)touches withEvent:(UIEvent *)event

{

NSLog
(@
"B - touchesBeagan.."
);

// 把事件传递下去给父View或包含他的ViewController

[
self
.nextResponder touchesBegan:touches withEvent:event];

}

  • (
    void
    )touchesCancelled:(
    NSSet
    *)touches withEvent:(UIEvent *)event

{

NSLog
(@
"B - touchesCancelled.."
);

// 把事件传递下去给父View或包含他的ViewController

[
self
.nextResponder touchesBegan:touches withEvent:event];

}

  • (
    void
    )touchesEnded:(
    NSSet
    *)touches withEvent:(UIEvent *)event

{

NSLog
(@
"B - touchesEnded.."
);

// 把事件传递下去给父View或包含他的ViewController

[
self
.nextResponder touchesBegan:touches withEvent:event];

}

  • (
    void
    )touchesMoved:(
    NSSet
    *)touches withEvent:(UIEvent *)event

{

NSLog
(@
"B - touchesMoved.."
);

// 把事件传递下去给父View或包含他的ViewController

[
self
.nextResponder touchesBegan:touches withEvent:event];

}

然后,在ViewA上就可以接收到touches消息,在ViewA上写:
[+ View Code](file:///Applications/WizNote.app/Contents/Resources/files/editor/index.html#)

这样就实现了向父View透传消息。
2.3 、不让ViewB收到消息,可以设置ViewB.UserInteractionEnable=NO;除了这样还可以override掉ViewB的ponitInside,原理参考上面。
在ViewB上写:
[+ View Code](file:///Applications/WizNote.app/Contents/Resources/files/editor/index.html#)

相关文章

  • iOS 事件以及手势的处理

    iOS 事件以及手势的处理 首先引用深入浅出iOS事件机制,iOS触摸事件处理详解,详解iOS触摸事件与手势识别三...

  • 《iOS事件触摸与手势》

    iOS事件触摸与手势 一、事件分发处理【由外到内】在iOS中发生触摸后,事件会加到UIApplication事件队...

  • iOS触摸事件处理

    iOS触摸事件处理 主要是记录下iOS的界面触摸事件处理机制,然后用一个实例来说明下应用场景.一、处理机制界面响应...

  • 详解iOS触摸事件与手势识别

    iOS最常见的是触摸事件Touch Events。触摸事件除了是view来处理,还有高级的手势可以处理。所以,本文...

  • iOS事件的响应者链

    iOS 事件响应者链 1 iOS中的事件 触摸事件 加速计事件 远程控制事件 在iOS中不是任何对象都能处理事件,...

  • iOS 触摸事件处理

    主要是记录下iOS的界面触摸事件处理机制,然后用一个实例来说明下应用场景. 一、处理机制 界面响应消息机制分两块,...

  • iOS触摸事件处理

    在开发过程中,大家或多或少的都会碰到令人头疼的手势冲突问题,正好前两天碰到一个类似的bug,于是借着这个机会了解了...

  • iOS触摸事件处理

    原文来自:http://www.cnblogs.com/Quains/p/3369132.html 有时间我再来整...

  • iOS-RunLoop浅析

    RunLoop是iOS事件响应与任务处理最核心的机制,它贯穿iOS整个系统,自动释放池,延迟处理,触摸事件,屏幕刷...

  • 事件处理

    事件处理 ios中的事件触摸事件(捏合,点击)加速计事件远程控制事件(耳机线控调整音量大小) 触摸事件 响应者对象...

网友评论

      本文标题:iOS触摸事件处理

      本文链接:https://www.haomeiwen.com/subject/mbtzlttx.html