博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
事件处理和手势操作
阅读量:6360 次
发布时间:2019-06-23

本文共 7622 字,大约阅读时间需要 25 分钟。

hot3.png

iOS中的事件分发

事件的分类

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

  • touchesBegan:withEvent:方法:一个或多个手指置于视图或窗口上

  • touchesMoved:withEvent:方法:一个或多个手指在移动

  • touchesEnded:withEvent:方法:一个或多个手指离开视图或窗口

  • touchesCancelled:withEvent:方法:如果其他系统事件(如内存不足警告)使得触摸被取消

Motion Events(运动事件)

  • motionBegan:withEvent:方法:运动事件开始

  • motionEnded:withEvent:方法:运动事件结束

  • motionCancelled:withEvent:方法:运动事件取消

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

    ```Objective-C

    import “ViewController.h”

    import

    ViewController () {

    BOOL acceptNextShake;
    }

    @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;

    }

    ```

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 
@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 
@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 () 
 {    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;

转载于:https://my.oschina.net/Steller/blog/601529

你可能感兴趣的文章
python之基本数据类型及深浅拷贝
查看>>
将bootstrap弹出框的点击弹出改为鼠标移入弹出
查看>>
SKF密码设备研究
查看>>
数据对象映射模式(通过工厂模式和注册树模式)v2
查看>>
4939 欧拉函数[一中数论随堂练]
查看>>
MySQL笔记(一)
查看>>
spring boot 包jar运行
查看>>
18年秋季学习总结
查看>>
Effective前端1:能使用html/css解决的问题就不要使用JS
查看>>
网络攻防 实验一
查看>>
由莫名其妙的错误开始---浅谈jquery的dom节点创建
查看>>
磨刀-CodeWarrior11生成的Makefile解析
查看>>
String StringBuffer StringBuilder对比
查看>>
bootstrap随笔点击增加
查看>>
oracle 中proc和oci操作对缓存不同处理
查看>>
[LeetCode] Spiral Matrix 解题报告
查看>>
60906磁悬浮动力系统应用研究与模型搭建
查看>>
指纹获取 Fingerprint2
查看>>
面试题目3:智能指针
查看>>
flask ORM: Flask-SQLAlchemy【单表】增删改查
查看>>