码迷,mamicode.com
首页 > 移动开发 > 详细

IOS事件传递及响应过程

时间:2015-07-25 18:30:29      阅读:361      评论:0      收藏:0      [点我收藏+]

标签:事件   手势   ios   events   

IOS事件传递及响应过程

–>事件到来 –>事件分发 –>事件响应

事件(Events)

1.触摸事件(Touch Events)(单点触摸、多点触摸及各种手势)

2.晃动事件(Motion Events) (重力、加速度等传感器)

3.远程控制事件(Remote-Control Events) (线控耳机、airplay)

事件分发(Event Delivery)

触摸事件:触摸->硬件中断->UIKit封装成UIEvent对象(针对触摸事件)-> 当前运行的应用程序的事件队列 -> UIApplication ->key window ->Hit-Testing View

其他事件:key window -> First Responder

目的(官方文档)

The ultimate goal of these event paths is to find an object that can handle and respond to an event. Therefore, UIKit first sends the event to the object that is best suited to handle the event. For touch events, that object is the hit-test view, and for other events, that object is the first responder.

方法:

Hit-Testing Returns the View Where a Touch Occurred Touch

The hit-test view is given the first opportunity to handle a touch event. If the hit-test view cannot handle an event, the event travels up that view’s chain of responders as described in “ The Responder Chain Is Made Up of Responder Objects ” until the system finds an object that can handle it.

The Responder Chain Is Made Up of Responder Objects (Motion Or R-C)

事件处理的事件传递说明

发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中,UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)

UIView不接受触摸事件的三种情况:

1.不接收用户交互时:userInteractionEnabled = NO;

2.当视图隐藏时:hidden = YES;

3.当视图透明时:alpha = 0.0~0.01

注意:UIImageView的userInteractionEnabled默认是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的

事件传递的详细过程:

当触摸发生时,主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,但是这仅仅是整个事件处理过程的第一步,找到合适的视图控件后,就会调用视图控件的touches方法来做具体的事件处理

开始触摸事件:

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

触摸时移动事件:

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

触摸结束事件:

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

这些touches方法的默认做法是将时间顺着响应链向上传递,将事件交给上一个响应者进行处理。

示例:

技术分享

响应者链条

示例:

技术分享

事件传递的完整过程

现将事件对象由上往下传递(由父控件传递给子控件),找到最合适的控件来处理这个事件。调用最合适控件的touches….方法 如果调用了[super touches….];就会将事件顺着响应者链条往上传递,传递给上一个响应者 接着就会调用上一个响应者的touches….方法

如何判断上一个响应者

如果当前这个view是控制器的view,那么控制器就是上一个响应者 如果当前这个view不是控制器的view,那么父控件就是上一个响应者

响应者链条的事件传递过程

如果view是控制器的view,就传递给控制器;如不是,则将其传递给它的父视图 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理 如果window对象也不处理,则其将事件或消息传递给UIApplication对象 如果UIApplication也不能处理该事件或消息,则将其丢弃

注意

为什么用队列管理事件,而不用栈?

队列先进先出,能保证先产生的事件先处理。栈先进后出。

代码展示:

技术分享

//具体功能:
//1.每个视图都可以经过触摸拖动,并且在触摸时会有方法的动画效果在(touchesBegin方法中实现)。
//2.当触摸结束是会有放大还原的动画效果 在(touchesEnd方法中实现)。
//3.当触摸其中任意一个视图时,该视图会随着手势一起移动,并且当移动视图的中心点(view.center)进入其他两个视图的frame中时,会将两个视图吸附进来,最后看上去只剩下一个视图 在(touchesMove方法中实现)。
//4.当双击父视图的任意空白处时,三个视图将以动画的效果回到起始位置 在(touchesBegin方法中实现)
#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *magentaView;
@property (weak, nonatomic) IBOutlet UIImageView *cyanView;
@property (weak, nonatomic) IBOutlet UIImageView *yellowView;

@end

#define kMagentaViewFrame   (CGRect){53,55,100,100}
#define kCyanViewFrame      (CGRect){132,254,100,100}
#define kYellowViewFrame    (CGRect){223,457,100,100}

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

}
//自定义方法,求出触摸点的位置返回location
- (CGPoint)locationInTouches:(NSSet *)touches
{
    // 0. 先取出触摸
    UITouch *touch = [touches anyObject];

    // 1. 返回触摸点(注意:坐标系 self.view)
    return [touch locationInView:self.view];
}
//自定义方法,判断触摸点是否在三个视图的frame中,是返回YES,该视图随着手势一起移动。
- (BOOL)isImageViewsContainsPoint:(CGPoint)location
{
    if (CGRectContainsPoint(_magentaView.frame, location)
        || CGRectContainsPoint(_cyanView.frame, location)
        || CGRectContainsPoint(_yellowView.frame, location)) {
        return YES;
    }

    return NO;
}
//自定义方法,当进行双击时,三个视图回到原来的位置
- (void)resetFrames
{
    [UIView animateWithDuration:0.5 animations:^{
        _cyanView.frame = kCyanViewFrame;
        _magentaView.frame = kMagentaViewFrame;
        _yellowView.frame = kYellowViewFrame;
    }];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    CGPoint location = [self locationInTouches:touches];

    // 0. 先取出触摸
    UITouch *touch = [touches anyObject];

    if ([self isImageViewsContainsPoint:location]) { // 触摸发生在三个视图里
        // 1. 取出触摸发生的视图
        UIImageView *view = (UIImageView *)touch.view;

        // 2. 设置触摸的视图的中心点为触摸点并放大触摸的视图
        [UIView animateWithDuration:0.5 animations:^{
            view.center = location;
            view.transform = CGAffineTransformMakeScale(1.2, 1.2);
        }];
    } else { // 执行双击操作
        if (touch.tapCount == 2) { // 双击
            [self resetFrames];
        }
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGPoint location = [self locationInTouches:touches];

    // 移动时的触摸点落在哪个视图的矩形区域内,那个视图的中心点就设置为触摸点
    if (CGRectContainsPoint(_magentaView.frame, location)) {
        [UIView animateWithDuration:0.3 animations:^{
            _magentaView.center = location;
        }];
    }

    if (CGRectContainsPoint(_cyanView.frame, location)) {
        [UIView animateWithDuration:0.3 animations:^{
            _cyanView.center = location;
        }];
    }

    if (CGRectContainsPoint(_yellowView.frame, location)) {
        [UIView animateWithDuration:0.3 animations:^{
            _yellowView.center = location;
        }];
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 0. 先取出触摸
    UITouch *touch = [touches anyObject];

    // 1. 取出触摸发生的视图
    UIImageView *view = (UIImageView *)touch.view;

    // 还原触摸的视图
    [UIView animateWithDuration:0.5 animations:^{
        view.transform = CGAffineTransformIdentity;
    }];
}


@end

版权声明:本文为博主原创文章,未经博主允许不得转载。

IOS事件传递及响应过程

标签:事件   手势   ios   events   

原文地址:http://blog.csdn.net/wow09_1225/article/details/47058141

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!