iOS开发系列课程(08) — 事件处理详解和手势操作手机开发
// 封装一个播放段音频的方法 - (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
事件是当用户手指触击屏幕及在屏幕上移动时,系统将事件按照特定的路径传递给可以对其进行处理的对象。在iOS中,一个UITouch对象表示一个触摸,一个UIEvent对象表示一个事件。事件对象中包含与当前多点触摸序列相对应的所有触摸对象,还可以提供与特定视图或窗口相关联的触摸对象。
响应者对象是可以响应事件并对其进行处理的对象。UIResponder是所有响应者对象的基类,它不仅为事件处理,而且也为常见的响应者行为定义编程接口。UIApplication、UIView和所有从UIView派生出来的UIKit类(包括UIWindow)都直接或间接地继承自UIResponder类。第一响应者是应用程序中当前负责接收触摸事件的响应者对象(通常是一个UIView对象)。UIWindow对象以消息的形式将事件发送给第一响应者,使其有机会首先处理事件。如果第一响应者没有进行处理,系统就将事件(通过消息)传递给响应者链中的下一个响应者,看看它是否可以进行处理。
事件的分发机制问题:当有多个重叠的UIView时,谁是第一响应者
默认的点击顺序是按照UIView中subviews的逆顺序 如果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
试着点击屏幕上圈出来的几个区域,看看会发生什么并解释为什么。
手势操作是通过使用者的手指触控,计算手指移动轨迹、坐标,然后对程序做相应处理的过程。手势操作需要添加手势识别器,所有手势识别器公共的父类是UIGestureRecognizer。
各种手势的使用下面的例子演示了如何使用手势操作实现图片的旋转和缩放以及如何通过长按手势在窗口上添加一个新的视图(一个篮球图片字符),运行效果如下图所示。
#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)来支持下面的操作:
两个手势可以同时被认可
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
手势与控件冲突
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
相关文章
- iOS 和 Android 哪个更利于赚钱呢详解手机开发
- iOS打电话功能详解手机开发
- IOS网络编程—(数据请求+slider)将网络上的大文件下载到本地,并打印其进度详解手机开发
- iOS发送邮件的代码详解手机开发
- iOS开发中对于NSURLRequest的封装详解手机开发
- iOS用ASIHttpRequest上传详解手机开发
- IOS中十六进制的颜色转换为UIColor详解手机开发
- iOS 获取手机的型号,系统版本,软件名称,软件版本详解手机开发
- iOS在程序中控制系统的屏幕亮度详解手机开发
- iOS使用代码截图详解手机开发
- ios网络编程详解手机开发
- iOS获取当前app版本详解手机开发
- IOS 雪花飘落效果详解手机开发
- ios生成三种随机数方法详解手机开发
- iOS开发笔记 – 工具篇详解手机开发
- iOS开发系列课程(03) — UIView详解手机开发
- iOS 11多项重大功能流出:Apple Pay或支持点对点支付详解手机开发
- IOS开发之逆向分析详解手机开发
- iOS AutoLayout全解详解手机开发
- 2017年校园招聘ios面试题详解手机开发
- iOS开发UI篇—自定义layer详解手机开发
- iOS—内存优化详解手机开发
- iOS开发—-地图与导航–定位和位置信息获取详解手机开发
- iOS上应用如何兼容32位系统和64位系统详解手机开发
- 基于Linux环境下iOS应用开发实践(linux下开发ios)