iOS开发学习之触摸事件和手势识别

 
iOS的输入事件

  • 触摸事件
  • 手势识别
  • 手机摇晃
一、iOS的输入事件
 
触摸事件(滑动、点击)
运动事件(摇一摇、手机倾斜、行走),不需要人为参与的
远程控制事件(耳机控制手机声音)
1⃣️iOS事件对象都是UIEvent类的实例
UIEvent类对事件类型定义了enum常量:
  • typedef NS_ENUM(NSInteger, UIEventType){
  • UIEventTypeTouches,
  • UIEventTypeMotion,
  • UIEventRemoteControl,
  • };
触摸事件必须是继承UIResponser的
 
二、触摸事件
1⃣️UIView,有4种处理不同的触摸事件
UIView是UIResponder的子类,可以覆盖下列4个方法处理不同的触摸事件。
1. 一根或者多根手指开始触摸屏幕
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
2.一根或者多根手指在屏幕上移动(随着手指的移动,会持续调用该方法)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
3.一根或者多根手指离开屏幕
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
4.触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
 
#pragma mark - UITouch事件
#pragma mark 触摸开始
 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
 {
     NSLog(@"触摸开始");
     for (UITouch *touch in touches) {
         NSLog(@"%@", touch);
     }
 }
 
#pragma mark 触摸移动
 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
 {
     NSLog(@"触摸移动Touch对象个数:%d",[touches count]);
     // 要移动界面上黄颜色的视图

     // 1. 得到当前手指的位置
     UITouch *touch = [touches anyObject];
     CGPoint location = [touch locationInView:self.view];
     // 2. 得到上一次手指的位置
     CGPoint preLocation = [touch previousLocationInView:self.view];
     // 3. 计算两个位置之间的偏移
     CGPoint offset = CGPointMake(location.x - preLocation.x, location.y - preLocation.y);
     // 4. 使用计算出来的偏移量,调整视图的位置
     [_demoView setCenter:CGPointMake(_demoView.center.x + offset.x, _demoView.center.y + offset.y)];

     // 完整的UITouch事件调试方法
     NSLog(@"触摸移动");
     for (UITouch *touch in touches) {
         NSLog(@"%@", touch);
     }
 }

 #pragma mark 触摸结束
 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
 {
     // 完整的UITouch事件调试方法
     NSLog(@"触摸完成");
     for (UITouch *touch in touches) {
         NSLog(@"%@", touch);
     }
 }

 #pragma mark 触摸中断
 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
 {
     // 完整的UITouch事件调试方法
     NSLog(@"触摸中断");
     for (UITouch *touch in touches) {
         NSLog(@"%@", touch);
     }
 }
 
Swift
 override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
         println("touchesBegan")

         //获取touches数量
         let numTouches = touches.count

         //获取点击屏幕的次数
         let tapTouches = (touches as NSSet).anyObject()?.tapCount

         //获取事件发生时间
         let timestamp = event.timestamp

         //获取当前相对于self.view的坐标
         let locationPoint = (touches as NSSet).anyObject()?.locationInView(self.view)

         //获取上一次相对于self.view的坐标
         let previousPoint = (touches as NSSet).anyObject()?.previousLocationInView(self.view)

         //允许使用手势
         self.view.userInteractionEnabled = true

         //支持多点触摸
         self.view.multipleTouchEnabled = true

         println("\(tapTouches)")

         //判断如果有两个触摸点

         {
             //获取触摸集合
             let twoTouches = (touches as NSSet).allObjects

             //获取触摸数组
             let first:UITouch = twoTouches[] as! UITouch //第1个触摸点
             let second:UITouch = twoTouches[]as! UITouch //第2个触摸点

             //获取第1个点相对于self.view的坐标
             let firstPoint:CGPoint = first.locationInView(self.view)

             //获取第1个点相对于self.view的坐标
             let secondPoint:CGPoint = second.locationInView(self.view)

             //计算两点之间的距离
             let deltaX = secondPoint.x - firstPoint.x;
             let deltaY = secondPoint.y - firstPoint.y;
             let initialDistance = sqrt(deltaX*deltaX + deltaY*deltaY )

             println("两点间距离是:\(initialDistance)")
         }
     }

     //手指在移动
 //    override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {

     //2015年5月2后修改
     override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {

         println("touchesMoved")
     }

     //触摸结束
 //    override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {

     //2015年5月2后修改
     override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {

         println("touchesEnded")
     }

     //触摸意外终止
     //模拟器演示:鼠标拖动的同时,按键盘command+shift+h 相当于点击手机home键,退出应用,触发touchesCancelled事件,在打电话、等情况下也会触发
 //    override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {

     //2015年5月2后修改
     override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {

         println("touchesCancelled")
     }
     
 
2⃣️触摸事件的处理
如果hit-test视图无法处理事件,则通过响应者链向上传递
1.如果hit-test视图的控制器存在,就传递给控制器;如果控制器不存在,则将其传递给它的父视图
2.如果视图或它的控制器无法处理收到的事件或消息,则将其传递给该视图的父视图
3.每一个在视图继承树中的上层视图如果不能处理收到的事件或消息,则重复上面的步骤1,2
4.在视图继承树的最上层视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给窗口对象进行处理
5. 如果窗口对象也不能进行处理,则其将事件或消息传递给UIApplication对象
6.如果UIApplication也不能处理该事件或消息,则将其丢弃
当用户点击屏幕时,会产生一个UITouch对象传递给UIApplication,然后由window负责查找最适合相应触摸事件的视图对象(hitTest,pointInside)
找到合适的视图之后,Touch方法由对应的视图完成,上级视图不再接管
3⃣️不接受处理事件的三种方法
不接收用户交互:userInteractionEnabled = NO;
隐藏:hidden = YES;
透明:alpha = 0~0.01
 
三、手势识别
1⃣️iOS目前支持的手势识别(6种)
UITapGestureRecognizer(点按)
UIPinchGestureRecognizer(捏合)
UIPanGestureRecognizer(拖动)
UISwipeGestureRecognizer(轻扫)
UIRotationGestureRecognizer(旋转)
UILongPressGestureRecognizer(长按)
2⃣️手势识别的使用方法(4步)
通常在视图加载的时候定义(UIGestureRecognizer是抽象类,需要实例化使用)
创建手势识别实例
设置手势识别属性,例如手指数量,方向等
将手势识别附加到指定的视图之上
编写手势触发响应方法
3⃣️手势识别的状态(7个)
   1.  // 没有触摸事件发生,所有手势识别的默认状态
    UIGestureRecognizerStatePossible,
    // 一个手势已经开始但尚未改变或者完成时
    UIGestureRecognizerStateBegan,
    // 手势状态改变
    UIGestureRecognizerStateChanged,
    // 手势完成
    UIGestureRecognizerStateEnded,
    // 手势取消,恢复至Possible状态
    UIGestureRecognizerStateCancelled, 
    // 手势失败,恢复至Possible状态
    UIGestureRecognizerStateFailed,
    // 识别到手势识别
    UIGestureRecognizerStateRecognized =UIGestureRecognizerStateEnded 
  2.手势识别的属性
  • state——手势状态view——手势发生视图
常用方法
locationInView 获得手势发生对应视图所在位置
 - (void)viewDidLoad
 {
     [super viewDidLoad];

     // 根据实例化方法,我们知道:
     // 1.有一个处理消息的对象,应该是self
     // 2.我们需要定义一个方法,当手势识别检测到的时候,运行
     UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapAction:)];
     // setNumberOfTapsRequired 点按次数
     [tap setNumberOfTapsRequired:];
     // setNumberOfTouchesRequired 点按的手指数量
     [tap setNumberOfTouchesRequired:];
     // 把手势识别增加到视图上
     [self.demoView addGestureRecognizer:tap];

     UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinchAction:)];
     [self.demoView addGestureRecognizer:pinch];

     UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotationAction:)];
     [self.demoView addGestureRecognizer:rotation];

     UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panAction:)];
     [self.demoView addGestureRecognizer:pan];

     UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPressAction:)];
     [self.demoView addGestureRecognizer:longPress];

     // 向左扫
     UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];
     [swipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
     [self.view addGestureRecognizer:swipeLeft];
     // 向右扫
     UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];
     [swipeRight setDirection:UISwipeGestureRecognizerDirectionRight];
     [self.view addGestureRecognizer:swipeRight];
     // 向上扫
     UISwipeGestureRecognizer *swipeTop = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];
     [swipeTop setDirection:UISwipeGestureRecognizerDirectionUp];
     [self.view addGestureRecognizer:swipeTop];
     // 向下扫
     UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];
     [swipeDown setDirection:UISwipeGestureRecognizerDirectionDown];
     [self.view addGestureRecognizer:swipeDown];
 }

 - (void)didReceiveMemoryWarning
 {
     [super didReceiveMemoryWarning];
     // Dispose of any resources that can be recreated.
 }
#pragma mark - 轻扫手势
 - (void)swipeAction:(UISwipeGestureRecognizer *)sender
 {
     NSLog(@"%d", sender.direction);
     switch (sender.direction) {
         case UISwipeGestureRecognizerDirectionLeft:
             NSLog(@"向左扫");
             break;
         case UISwipeGestureRecognizerDirectionRight:
             NSLog(@"向右扫");
             break;
         case UISwipeGestureRecognizerDirectionUp:
             NSLog(@"向上扫");
             break;
         case UISwipeGestureRecognizerDirectionDown:
             NSLog(@"向下扫");
             break;
         default:
             break;
     }
 }
#pragma mark - 长按手势
 - (void)longPressAction:(UILongPressGestureRecognizer *)sender
 {
     // 我们可以利用demoView的Tag属性,默认时tag=0
     // 如果tag=0,我们放大一倍,否则,我们缩小一半
     CGFloat scale;
     ) {
         scale = 2.0;
         _demoView.tag = ;
     } else {
         scale = 0.5;
         _demoView.tag = ;
     }

     sender.view.transform = CGAffineTransformScale(sender.view.transform, scale, scale);
 }
  
#pragma mark - 拖放手势
 - (void)panAction:(UIPanGestureRecognizer *)sender
 {
     // 在拖放手势中是需要考虑手指的状态的UIGestureRecognizerState
     // 在拖放手势中使用的状态是UIGestureRecognizerStateChanged
     // 通常在使用拖放手势的时候,当手指离开的时候,应该做一个很小的动作,提醒用户拖放完成
     if (sender.state == UIGestureRecognizerStateChanged) {
         // locationInView
         [_demoView setCenter:[sender locationInView:self.view]];
     } else if (sender.state == UIGestureRecognizerStateEnded) {
         [_demoView setBackgroundColor:[UIColor yellowColor]];
     }
 }
#pragma mark - 旋转手势
 - (void)rotationAction:(UIRotationGestureRecognizer *)sender
 {
     sender.view.transform = CGAffineTransformRotate(sender.view.transform, sender.rotation);

     // 和捏合操作类似,旋转角度同样需要方福伟
     sender.rotation = 0.0f;
 }

 #pragma mark - 捏合手势
 - (void)pinchAction:(UIPinchGestureRecognizer *)sender
 {
     // 有关转换的内容,我们在后续动画部分再继续
     sender.view.transform = CGAffineTransformScale(sender.view.transform, sender.scale, sender.scale);

     // 缩放功能很简单,但是不要忘记将比例复位
     sender.scale = 1.0f;
     NSLog(@"捏我了");
 }

 #pragma mark - 点按手势
 - (void)tapAction:(UITapGestureRecognizer *)sender
 {

     NSLog(@"点我了 %@", sender);
 }

 #pragma mark - 手势触摸事件
 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
 {
     NSLog(@"触摸事件!");
     // 1. 先取出UITouch对象
     // 2. 判断响应点击的UIView是不是我们需要的
     UITouch *touch = [touches anyObject];
     if ([touch view] == _imageView) {
         NSLog(@"点到图像了!");
     }
 }

Swift:

添加手势

         //点击事件
         var atap = UITapGestureRecognizer(target: self, action: "tapDo:")
         self.view.addGestureRecognizer(atap)
         atap.numberOfTapsRequired =  //单击次数
         atap.numberOfTouchesRequired =  //手指个数

         //拖动事件
         var aPan = UIPanGestureRecognizer(target: self, action: "handlenPan:")
         self.view.addGestureRecognizer(aPan)
         aPan.minimumNumberOfTouches =  //最少手指个数
         aPan.maximumNumberOfTouches =  //最多手指个数

         //长按事件
         var aLongPress = UILongPressGestureRecognizer(target: self, action: "longPress:")
         self.view.addGestureRecognizer(aLongPress)
         aLongPress.minimumPressDuration =  //需要长按的时间,最小0.5s

         //捏合事件
         var aPinch = UIPinchGestureRecognizer(target: self, action: "pinchDo:")
         self.view.addGestureRecognizer(aPinch)

         //旋转事件
         var aRotation = UIRotationGestureRecognizer(target: self, action: "rotatePiece:")
         self.view.addGestureRecognizer(aRotation)

         //轻扫事件--左轻扫
         var leftSwipe = UISwipeGestureRecognizer(target: self, action: "leftSwipe:")
         self.view.addGestureRecognizer(leftSwipe)
         leftSwipe.direction =  UISwipeGestureRecognizerDirection.Left

         //轻扫事件--右轻扫
         var rightSwipe = UISwipeGestureRecognizer(target: self, action: "rightSwipe:")
         self.view.addGestureRecognizer(rightSwipe)
         rightSwipe.direction =  UISwipeGestureRecognizerDirection.Right

         //轻扫事件--上轻扫
         var upSwipe = UISwipeGestureRecognizer(target: self, action: "upSwipe:")
         self.view.addGestureRecognizer(upSwipe)
         upSwipe.direction =  UISwipeGestureRecognizerDirection.Up

         //轻扫事件--下轻扫
         var downSwipe = UISwipeGestureRecognizer(target: self, action: "downSwipe:")
         self.view.addGestureRecognizer(downSwipe)
         downSwipe.direction =  UISwipeGestureRecognizerDirection.Down
     }

实现

     //手势

     //点击事件
     func tapDo(sender:UITapGestureRecognizer)
     {

         println("点击事件")
     }

     //拖动事件
     func handlenPan(sender:UIPanGestureRecognizer)
     {
         println("拖动事件")

         if sender.state == .Began
         {
             //拖动开始
         }
         else if sender.state == .Changed
         {
             //拖动过程
         }
         else if sender.state == .Ended
         {
             //拖动结束
         }
     }

     //长摁事件
     func longPress(sender:UILongPressGestureRecognizer)
     {
         println("长摁事件")

     }

     //捏合事件
     func pinchDo(sender:UIPinchGestureRecognizer)
     {
         println("捏合")
     }

     //旋转事件
     func rotatePiece(sender:UIRotationGestureRecognizer)
     {
         println("旋转")
     }

     //轻扫事件--左轻扫
     func leftSwipe(sender:UISwipeGestureRecognizer)
     {
         println("左轻扫")
     }

     //轻扫事件--右轻扫
     func rightSwipe(sender:UISwipeGestureRecognizer)
     {
         println("右轻扫")
     }

     //轻扫事件--上轻扫
     func upSwipe(sender:UISwipeGestureRecognizer)
     {
         println("上轻扫")
     }

     //轻扫事件--下轻扫
     func downSwipe(sender:UISwipeGestureRecognizer)
     {
         println("下轻扫")
     }
 
四、手机摇晃
 . 新建摇晃监听视图ShakeListenerView,并且设置canBecomeFirstResponder返回YES
 - (BOOL)canBecomeFirstResponder
 {
     return YES;
 }
 . 在Storyboard中将ViewController的View的Class设置为:ShakeListenerView
 . 在ViewController.m文件中增加:viewDidAppear和viewDidDisappear在视图出现和消失时成为/撤销第一响应者身份
 . 在视图控制器中增加手势监听方法:
 - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
 {
     if (event.subtype == UIEventSubtypeMotionShake) {
         NSLog(@"shake phone");
     }
 }
  #pragma mark - 要让ViewController支持摇晃,需要写三个方法
 // 1. 成为第一响应者,视图一出现时,就应该成为第一响应者
 - (void)viewDidAppear:(BOOL)animated
 {
     [self.view becomeFirstResponder];
     // 不要忘记去实现父类方法
     [super viewDidAppear:animated];
 }

 // 2. 注销第一响应者,视图要关闭的时候,注销
 - (void)viewDidDisappear:(BOOL)animated
 {
     [self.view resignFirstResponder];
     // 不要忘记去实现父类方法
     [super viewDidDisappear:animated];
 }

 // 3. 监听并处理移动事件,判断是否摇晃了手机
 - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
 {
     if (motion == UIEventSubtypeMotionShake) {
         NSLog(@"摇啊摇,摇到外婆桥!!!");
     }
 }
 

ios开发——实用技术OC-Swift篇&触摸与手势识别的更多相关文章

  1. ios开发——实用技术总结Swift篇&swift常用开发技术总结

    swift常用开发技术总结 懒加载:属性,数组(字典),控件... 数组(懒加载): lazy var shops:Array<Dictionary<String, String>& ...

  2. iOS开发——实用技术OC篇&单例模式的实实现(ACR&MRC)

    单例模式的实实现(ACR&MRC) 在iOS开发中单例模式是一种非常常见的模式,虽然我们自己实现的比较少,但是,系统却提供了不少的到来模式给我们用,比如最常见的UIApplication,No ...

  3. iOS开发——实用技术OC篇&事件处理详解

    事件处理详解 一:事件处理 事件处理常见属性: 事件类型 @property(nonatomic,readonly) UIEventType     type; @property(nonatomic ...

  4. ios开发——实用技术篇Swift篇&多点触摸与手势识别

    多点触摸与手势识别 //点击事件 var atap = UITapGestureRecognizer(target: self, action: "tapDo:") self.vi ...

  5. iOS开发——技术精华Swift篇&Swift 2.0和Objective-C2.0混编之第三方框架的使用

    swift 语言是苹果公司在2014年的WWDC大会上发布的全新的编程语言.Swift语言继承了C语言以及Objective-C的特性,且克服了C语言的兼容性问题.Swift语言采用安全编程模式,且引 ...

  6. iOS开发——新特性Swift篇&Swift 2.0 异常处理

    Swift 2.0 异常处理 WWDC 2015 宣布了新的 Swift 2.0. 这次重大更新给 Swift 提供了新的异常处理方法.这篇文章会主要围绕这个方面进行讨论. 如何建造异常类型? 在 i ...

  7. ios开发——实用技术OC-Swift篇&本地通知与远程通知详解

    本地通知与远程通知详解 一:本地通知   Local Notification的作用 Local Notification(本地通知) :是根据本机状态做出的通知行为,因此,凡是仅需依赖本机状态即可判 ...

  8. iOS开发——实用技术OC篇&简单抽屉效果的实现

    简单抽屉效果的实现 就目前大部分App来说基本上都有关于抽屉效果的实现,比如QQ/微信等.所以,今天我们就来简单的实现一下.当然如果你想你的效果更好或者是封装成一个到哪里都能用的工具类,那就还需要下一 ...

  9. iOS开发——混编Swift篇&OC移植为swift

    将Ojective-C代码移植转换为Swift代码 2015-03-09 15:07发布:yuhang浏览:201   相比于Objective-C,Swift语言更加简练.有时我们需要把原来写的一些 ...

随机推荐

  1. 浏览器兼容问题系列---使IE支持CSS3 Media Quary

    兼容是一件很让前端攻城师头疼的事情,笔者今天在做一个Demo的时候就碰到了一个问题(大牛就不要拍砖了,谢谢!) 经常做移动互联网前端的攻城师想必对于css3 media quary已经很熟悉了,但是碰 ...

  2. javascript 一些需要知道的东西

    这里我直接贴出代码,注释已经补全,欢迎指正: <script type="text/javascript"> /** 1,js中一切皆是对象,函数也是, 2,当定义变量 ...

  3. php编译参数注解--不明白许多参数的作用 慎用 –with-curlwrappers参数

    在Linux下安装PHP,源代码方式安装,总需要配置很多参数.这里列出常用配置参数,并详细用中文解释说明了.给大家一些参考 编译PHP的时候慎用 –with-curlwrappers参数 ./conf ...

  4. Hbase 建表基本命令总结

    访问hbase,以及操作hbase,命令不用使用分号 hbase shell 进入hbase list 查看表 hbase shell -d hbase(main):024:0> scan '. ...

  5. Initializing nested object properties z

    public class Employee { public Employee() { this.Insurance = new Insurance(); } // Perhaps another c ...

  6. [OFBiz]简介 一

    1.What is Apache OFBiz?http://ofbiz.apache.org/ 2.概述http://baike.baidu.com/view/638900.html?fromTagl ...

  7. (二)NUnit单元测试心得

    现在接着上次说到的内容,如何在项目中进行单元测试.由于做了一些调整,我上次发的内容,我这次也会重新发一次,请认真看看. 一.软件开发过程中存在的问题(没有使用单元测试的情况下) 难于定位bug的位置 ...

  8. CodeForce---Educational Codeforces Round 3 USB Flash Drives (水题)解题报告

    对于这题明显是用贪心算法来解决问题: 下面贴出笔者的代码: #include<cstdio> #include<iostream> #include<algorithm& ...

  9. 【HTML】Advanced7:Embedded Content: Video, Audio, and Canvas

    1.video <video src="kitties.mp4" poster="fluffy.jpg"(display before video is ...

  10. class0513(html基础加强2)

    使用VS创建网页 新建Web项目(新建→ASP.Net Web应用程序),新建html页面(添加→新建项→Web→HTML页) 查看页面的方式: 切换到“设计”视图,可以在这里查看初步的预览效果,不是 ...