首页 > 其他分享 >iOS开发系列课程(08) --- 事件处理详解和手势操作

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

时间:2023-06-20 14:35:13浏览次数:49  
标签:事件处理 08 iOS 视图 void 事件 imageView 手势 self


iOS中的事件分发

事件的分类

  1. Touch Events(多点触摸事件)
  • touchesBegan:withEvent:方法:一个或多个手指置于视图或窗口上
  • touchesMoved:withEvent:方法:一个或多个手指在移动
  • touchesEnded:withEvent:方法:一个或多个手指离开视图或窗口
  • touchesCancelled:withEvent:方法:如果其他系统事件(如内存不足警告)使得触摸被取消
  1. 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
  1. 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

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

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

响应者链处理原则

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

iOS中的手势操作

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

各种手势的使用

  • 点击手势:UITapGestureRecognizer
  • 长按手势:UILongPressGestureRecognizer
  • 旋转手势:UIRotationGestureRecognizer
  • 捏合手势:UIPinchGestureRecognizer
  • 滑动手势:UISwipeGestureRecognizer
  • 拖动手势:UIPanGestureRecognizer

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

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

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

  

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

#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文件如下图所示:

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

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

  1. 两个手势可以同时被认可
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
  1. 手势与控件冲突
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;


标签:事件处理,08,iOS,视图,void,事件,imageView,手势,self
From: https://blog.51cto.com/u_16166070/6522332

相关文章

  • iOS开发系列课程(05) --- 导航视图控制器
    简介  导航视图控制器是一个特殊的容器视图控制器,它可以维护有明确层次关系的视图之间的切换。我们可以打开模拟器或者你的iPhone看看设置功能,这里就是一个典型的对导航视图控制器的应用,如下图所示。很明显,导航视图控制器维护了一个栈结构,这是一种先进后出(FILO)的结构,我们将一个一......
  • iOS开发系列课程(09) --- 滚动视图
    UIScrollView入门  移动设备的屏幕⼤小是极其有限的,因此直接展⽰在⽤户眼前的内容也相当有限,当展⽰的内容较多超出一个屏幕时,用户可通过滚动操作来查看屏幕以外的内容,普通的UIView不具备滚动功能,不能显⽰过多的内容。UIScrollView是一个能够滚动的视图控件,可以⽤用来展⽰大量的......
  • iOS开发笔记 - 用CocoaPods管理第三方库
    在iOS项目中使用第三方类库可以说是非常常见的事,但是要正确配置这些第三方库会非常的繁琐,还好我们有CocoaPods来做这件事情,就如同在Java的世界里有Maven和Gradle,当然Maven的作用不仅仅是第三依赖库管理。通过CocoaPods工具我们可以为项目添加被称为"Pods"的依赖库(这些类库必须是Coc......
  • iOS开发笔记 - App上架流程(视频分享)
    具体的文档可以看一下我的《iOS开发笔记-上线流程》iOS项目上线流程视频百度云盘分享下面是一些相关的官方文档:https://developer.apple.com/app-store/review/guidelines/-项目审核指南http://www.apple.com/legal/intellectual-property/guidelinesfor3rdparties.htmlhttps......
  • Windows 2008服务器多界面和IIS的安装教程 140.210.16.x
    当你在使用服务器时是否有遇到这样一个问题?当你正在服务器里进行工作时,突然一个小伙伴在没有告知你的情况下进入了服务器里,导致你服务器失去连接了,这种情况是非常常见的现象。主要原因就是因为服务器没有安装多界面,服务器多开界面是占用的同一台服务器的资源,服务器多开数量没有限制......
  • FPGA电机控制源码(verilog+nios2架构)FPGA电机控制源码, 方案为单FPGA方案才用底层ver
    FPGA电机控制源码(verilog+nios2架构)FPGA电机控制源码,方案为单FPGA方案才用底层verilog+应用层nios2的软件架构,很具有学习价值。包括编码器模块算法,坐标变换算法,矢量调制算法等等。注:此代码不适合新手小白。FPGA电机控制源码是一个用于控制电机的程序代码,采用了FPGA(现场可......
  • JavaScript中Web应用程序事件处理
    通过下面的代码来绑定事件处理代码,不仅可以为同一事件源的同一事件重复绑定事件处理代码,还可以在只做一次浏览器兼容性检测的情况下完成所有的事件处理绑定。代码如下所示:js/mylib.jsvaraddEvent=function(target,name,fn){if(target.addEventListener)addEven......
  • iOS开发系列课程预告
    最近在Mac和iOS上做开发,觉得应该写一点东西分享给感兴趣的童鞋们。在此之前,曾经有很多同行们都在埋怨苹果Objective-C的复杂和难以上手,为此也有很多人对今年(2014年)刚推出的Swift抱有很多幻想。首先在现阶段甚至五年以内,我个人感觉Mac和iOS的开发可以说仍然离不开Objective-C,即便是......
  • VS2008开发的基于WinCE的网络服务器端和客户端程序多线程,线程同步,TCP/IP网络通讯、阻
    VS2008开发的基于WinCE的网络服务器端和客户端程序多线程,线程同步,TCP/IP网络通讯、阻塞式套接字发送数据与接收数据、……提供VC++源码以及固高嵌入式运动控制器的源代码,顾高运动控制器通过OtoStudio的ST语言编写,5轴电子凸轮,三轴电子齿轮控制同步带,一轴跟随主轴加速、同步、减速、......
  • Palera1n越狱简体中文,iOS15.0~16.5越狱支持Mac/Linux/U盘多平台
    Palera1n越狱简体中文,iOS15.0~16.5越狱支持Mac/Linux/U盘多平台中文教程:https://dkxuanye.cn/?p=6813官方文档:https://github.com/palera1n/palera1n/releases......