iOS开发系列课程(08) --- 事件处理详解和手势操作

来源:互联网 发布:linux统计登陆用户数 编辑:程序博客网 时间:2024/04/26 07:04

iOS中的事件分发

事件的分类

  1. Touch Events(多点触摸事件)

    • touchesBegan:withEvent:方法:一个或多个手指置于视图或窗口上
    • touchesMoved:withEvent:方法:一个或多个手指在移动
    • touchesEnded:withEvent:方法:一个或多个手指离开视图或窗口
    • touchesCancelled:withEvent:方法:如果其他系统事件(如内存不足警告)使得触摸被取消
  2. Motion Events(运动事件)

    • motionBegan:withEvent:方法:运动事件开始
    • motionEnded:withEvent:方法:运动事件结束
    • motionCancelled:withEvent:方法:运动事件取消

    说明:如果要摇一摇之类的应用,就可以使用运动事件进行处理,代码如下所示。

    #import "ViewController.h"#import <AVFoundation/AVFoundation.h>@interface ViewController () {    BOOL acceptNextShake;}@end@implementation ViewController// 封装一个播放段音频的方法 - (void)playSoundEffect:(NSString *)name withCallback:(void (*)(SystemSoundID, void *)) callback {    NSString *audioFile = [[NSBundle mainBundle] pathForResource:name ofType:nil];    NSURL *fileUrl = [NSURL fileURLWithPath:audioFile];    SystemSoundID soundID;    // 在系统中创建一个音效对象并获得其唯一ID    AudioServicesCreateSystemSoundID((__bridge CFURLRef)(fileUrl), &soundID);    // 注册在播放完之后执行的回调函数    // 第二个和第三个参数跟循环播放有关    // 第五个参数是指向传给回调函数的数据的指针    AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, callback, NULL);    // 播放音效    AudioServicesPlaySystemSound(soundID);    // 播放音效并震动    // AudioServicesPlayAlertSound(soundID);}// 摇一摇开始播放金币掉下的短音频- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {    if(acceptNextShake) {        acceptNextShake = NO;        [self playSoundEffect:@"4679.mp3" withCallback:nil];        // 阻止播放音效文件5秒钟        dispatch_async(dispatch_get_global_queue(0, 0), ^{        sleep(5);        acceptNextShake = YES;        });    }}- (void)viewDidLoad {    [super viewDidLoad];    acceptNextShake = YES;}@end
  3. Remote-Control Events(远程控制事件)

    • remoteControlReceivedWithEvent:方法:接收到远程控制事件

事件概述

  事件是当用户手指触击屏幕及在屏幕上移动时,系统将事件按照特定的路径传递给可以对其进行处理的对象。在iOS中,一个UITouch对象表示一个触摸,一个UIEvent对象表示一个事件。事件对象中包含与当前多点触摸序列相对应的所有触摸对象,还可以提供与特定视图或窗口相关联的触摸对象。

  响应者对象是可以响应事件并对其进行处理的对象。UIResponder是所有响应者对象的基类,它不仅为事件处理,而且也为常见的响应者行为定义编程接口。UIApplication、UIView和所有从UIView派生出来的UIKit类(包括UIWindow)都直接或间接地继承自UIResponder类。第一响应者是应用程序中当前负责接收触摸事件的响应者对象(通常是一个UIView对象)。UIWindow对象以消息的形式将事件发送给第一响应者,使其有机会首先处理事件。如果第一响应者没有进行处理,系统就将事件(通过消息)传递给响应者链中的下一个响应者,看看它是否可以进行处理。

事件的分发机制

问题:当有多个重叠的UIView时,谁是第一响应者

  1. 默认的点击顺序是按照UIView中subviews的逆顺序
  2. 如果UIView的同级别subviews中有重叠的部分,则优先检查顶部的subview,如果顶部的subview返回nil,再检查底部的subview。

请看下面的例子:

#import <UIKit/UIKit.h>@interface CDMyView : UIView@property (nonatomic, copy) NSString *name;@end
#import "CDMyView.h"@implementation CDMyView- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {    NSLog(@"%@", event);    NSLog(@"%@", self.name);}@end
#import <UIKit/UIKit.h>@interface CDThyView : UIView@property (nonatomic, copy) NSString *name;@end
#import "CDThyView.h"@implementation CDThyView@end
#import "ViewController.h"#import "CDMyView.h"#import "CDThyView.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    CDMyView *view1 = [[CDMyView alloc] initWithFrame:CGRectMake(50, 50, 275, 500)];    view1.backgroundColor = [UIColor redColor];    view1.name = @"view1";    CDMyView *view2 = [[CDMyView alloc] initWithFrame:CGRectMake(20, 20, 230, 200)];    view2.backgroundColor = [UIColor orangeColor];    view2.name = @"view2";    CDThyView *view3 = [[CDThyView alloc] initWithFrame:CGRectMake(20, 240, 230, 320)];    view3.backgroundColor = [UIColor yellowColor];    view3.name = @"view3";    CDMyView *view4 = [[CDMyView alloc] initWithFrame:CGRectMake(20, 20, 100, 150)];    view4.backgroundColor = [UIColor greenColor];    view4.name = @"view4";    CDMyView *view5 = [[CDMyView alloc] initWithFrame:CGRectMake(20, 40, 240, 60)];    view5.backgroundColor = [UIColor cyanColor];    view5.name = @"view5";    [self.view addSubview:view1];    [view1 addSubview:view2];    [view1 addSubview:view3];    [view2 addSubview:view4];    [view4 addSubview:view5];}@end

  试着点击屏幕上圈出来的几个区域,看看会发生什么并解释为什么。

这里写图片描述

响应者链处理原则

  1. 点击检测视图或者第一响应者传递事件或动作消息给它的视图控制器(如果它有的话);如果没有一个视图控制器,就传递给它的父视图。
  2. 如果一个视图或者它的视图控制器不能处理这个事件或动作消息,它将传递给该视图的父视图。
  3. 在这个视图层次中的每个后续的父视图遵循上述的模式,如果它不能处理这个事件或动作消息的话。
  4. 最顶层的视图如果不能处理这个事件或动作消息,就传递给UIWindow对象来处理。
  5. 如果UIWindow 对象不能处理,就传给单件应用程序对象UIApplication。
  6. 如果应用程序对象也不能处理这个事件或动作消息,将抛弃它。

iOS中的手势操作

  手势操作是通过使用者的手指触控,计算手指移动轨迹、坐标,然后对程序做相应处理的过程。手势操作需要添加手势识别器,所有手势识别器公共的父类是UIGestureRecognizer。

各种手势的使用

  • 点击手势:UITapGestureRecognizer

  • 长按手势:UILongPressGestureRecognizer

  • 旋转手势:UIRotationGestureRecognizer

  • 捏合手势:UIPinchGestureRecognizer

  • 滑动手势:UISwipeGestureRecognizer

  • 拖动手势:UIPanGestureRecognizer

这里写图片描述

  下面的例子演示了如何使用手势操作实现图片的旋转和缩放以及如何通过长按手势在窗口上添加一个新的视图(一个篮球图片字符),运行效果如下图所示。

这里写图片描述    这里写图片描述

#import "ViewController.h"@interface ViewController () <UIGestureRecognizerDelegate> {    UIImageView *imageView;}@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    self.view.backgroundColor = [UIColor blackColor];    // 创建UIImage对象并获得其尺寸    UIImage *image = [UIImage imageNamed:@"Dudu.jpg"];    CGSize imageSize = image.size;    // 用UIImage创建UIImageView并执行其位置和尺寸    imageView = [[UIImageView alloc] initWithImage:image];    CGRect rect = self.view.bounds;    imageView.frame = CGRectMake((rect.size.width - imageSize.width) / 2, (rect.size.height - imageSize.height) / 2, imageSize.width, imageSize.height);    // 设置允许用户交互行为    imageView.userInteractionEnabled = YES;    // 创建捏合手势识别器并添加到上面的UIImageView上    UIPinchGestureRecognizer *r1 = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(doPinch:)];    [imageView addGestureRecognizer:r1];    // 给手势识别器绑定委托    r1.delegate = self;    // 创建旋转手势识别器并添加到上面的UIImageView上    UIRotationGestureRecognizer *r2 = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(doRotate:)];    [imageView addGestureRecognizer:r2];    // 给手势识别器绑定委托    r2.delegate = self;    // 连续3次点击删除图片    UITapGestureRecognizer *r3 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doRemove)];    // 设置需要3次点击    r3.numberOfTapsRequired = 3;    [imageView addGestureRecognizer:r3];    // 添加一个长按手势识别器    UILongPressGestureRecognizer *r4 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(doAddBall:)];    r4.minimumPressDuration = 1;    // 至少按住1秒钟    [self.view addGestureRecognizer:r4];    [self.view addSubview:imageView];}- (void) doPinch:(UIPinchGestureRecognizer *) sender {     // 通过放射变换实现图片缩放    imageView.transform = CGAffineTransformScale(imageView.transform, sender.scale, sender.scale);    // 防止效果叠加    sender.scale = 1;}- (void) doRotate:(UIRotationGestureRecognizer *) sender {    // 通过放射变换实现图片旋转    imageView.transform = CGAffineTransformRotate(imageView.transform, sender.rotation);    // 防止效果叠加    sender.rotation = 0;}- (void) doRemove {    [imageView removeFromSuperview];}- (void) doAddBall:(UILongPressGestureRecognizer *) sender {    // 对手势做一个状态判断:只有在刚识别到长按手势时才绘制篮球    if(sender.state == UIGestureRecognizerStateBegan) {        // 获取长按的位置在屏幕上对应的点        CGPoint point = [sender locationInView:self.view];        UIView *tempView = [[[NSBundle mainBundle] loadNibNamed:@"CDBallView" owner:self options:nil] lastObject];        // 将手指按下的位置作为新视图的中心点        tempView.center = point;        [self.view addSubview:tempView];    }}// 同时支持多个手势操作的回调方法- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {    // 有没有什么情况只能支持一个手势呢?    return YES;}@end

  上面的例子中使用的XIB文件如下图所示:

这里写图片描述

  手势识别器也可以设置委托(UIGestureRecognizerDelegate)来支持下面的操作:

  1. 两个手势可以同时被认可

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
  2. 手势与控件冲突

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 注册过万方医学网忘了用户名怎么办 狗咬了没破皮没出血有点疼怎么办 狗咬了没出血肿起来了怎么办 广州已经过了幼儿园报名时间怎么办 大专学费没交学校开始查了怎么办 如果申请留学的本科成绩不够怎么办 硕士读了三年无法毕业怎么办啊 孩子在美国读研读不下去怎么办? 在地割草中过失死亡法律^怎么办 高中毕业申请国外大学没录取怎么办 英国研究生老师没给写推荐信怎么办 申请悉尼大学博士奖学金被拒怎么办 硕士延迟毕业但被博士录取怎么办 考完初级职称还是不会做账怎么办 美国留学生在中国办日本签证怎么办 留学雅思过了gpa低怎么办澳洲 护士电子化注册用户名忘记了怎么办 护士电子化注册证书编码错误怎么办 澳洲预科上半学期成绩不达标怎么办 美国大学绩点不够怎么办学习证明 研一想换导师导师不答应怎么办 日本留学在留下来不想去了怎么办 加拿大工签3年到期了怎么办 鞋子穿久了会有臭味怎么办 考研忘了自己填写的通讯地址怎么办 基础教育教师培训网注册错了怎么办 11个月宝宝便秘大便有血怎么办 两岁宝宝两天没拉粑粑了怎么办 两岁宝宝两天没拉大便怎么办 两岁宝宝便秘两天没拉怎么办 昨天带孩子上早教课一直哭怎么办 网页账号注册无法获取验证码怎么办 我总是为一些事情而烦恼怎么办 手机键盘打出的字是繁体字怎么办 阴阳师协助任务对方接了不做怎么办 wow牧师选错了圣物怎么办 淘宝有几个订单被管控了怎么办 埋线双眼皮一个宽一个窄怎么办 把维D和维C一起吃了怎么办 微信出现当前登录环境异常该怎么办 去麦加朝觐人要出现死亡怎么办