zoukankan      html  css  js  c++  java
  • ios UIGestureRecognizer

    前言:在开始讲解这个类之前,我们回顾一下,在处理触摸屏事件中,还有没有别的方法?在前面讲解截图的那篇博文中,我使用过来自于UIResponder的几个方法:

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

    优点:可以响应所有的触屏操作

    缺点:甄别不同的手势操作非常麻烦,需要自己计算做不同的手势分辨,记录运行轨迹。

    于是,在ios3.2之后,苹果另外提供了一种更简便的方式,就是使用UIGestureRecognizer

    正文:先来看一下类的继承关系吧!

    UIGestureRecognizer是个抽象类,我们主要使用它的子类。

    ios的命名非常清晰,从名字中我们就可以看出各个子类的主要作用: Tap(点击)、Pinch(捏合,两指向内或向外捏动)、Rotation(旋转)、Swipe(滑动,快速移动,是用于监测滑动的方向的)、Pan (拖移,慢速移动,是用于监测偏移的量的)以及 LongPress(长按)。

    一、使用

    定义非常简单,关键就是不要忘了设置delegate,以及给要响应的view加上这个手势。至于点击响应,这个各有不同,我们会一一介绍的。对了,不要忘了,在.h文件里加上协议UIGestureRecognizerDelegate。

    注意:如果要给UIImageView 添加手势,那么一定要设置这个imageView.userInteractionEnabled = YES;否则不会有任何反应!

    //添加Pinch手势
    UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinchRecognizer:)];
    pinchRecognizer.delegate = self;
    [self.view addGestureRecognizer:pinchRecognizer];
    [pinchRecognizer release];

    1、Pinch手势的响应:

    -(void)handlePinchRecognizer:(id)sender
    {
        UIPinchGestureRecognizer *ges = (UIPinchGestureRecognizer *)sender;
        int touchCount = ges.numberOfTouches;//zhege ????????????????
        if(touchCount==2){
            if([ges state]== UIGestureRecognizerStateBegan){
                CGPoint p1 = [ges locationOfTouch:0 inView:self.view];
                CGPoint p2 = [ges locationOfTouch:1 inView:self.view];
                distStart = [self distanceFromPointX:p1 ToPointY:p2];
            }else if([ges state]== UIGestureRecognizerStateEnded){
                CGPoint p1 = [ges locationOfTouch:0 inView:self.view];
                CGPoint p2 = [ges locationOfTouch:1 inView:self.view];
                distEnd = [self distanceFromPointX:p1 ToPointY:p2];
                
                scale = distEnd/distStart; //计算缩放比例,如果scale>1,放大;如果scale<1,缩小
                float newWidth = _imageView.bounds.size.width * scale; //计算新的长、宽
                float newHeight = _imageView.bounds.size.height * scale;
                
                if (newWidth < self.view.bounds.size.width) {
                    newWidth = self.view.bounds.size.width;
                    newHeight = _imageView.bounds.size.height/_imageView.bounds.size.width * newWidth;
                }
                
                if (newHeight < self.view.bounds.size.height) {
                    newHeight = self.view.bounds.size.height;
                    newWidth = _imageView.bounds.size.width/_imageView.bounds.size.height * newHeight;
                }
                
                [_imageView setFrame:CGRectMake(0, 0, newWidth, newHeight)];
                 _scrollView.contentSize = _imageView.bounds.size;
                [_scrollView setFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
            }
        }//touchCount
    }
    //计算两点之间的距离
    -(float)distanceFromPointX:(CGPoint) start ToPointY:(CGPoint) end
    {
        float distance;
        CGFloat xDist = end.x - start.x;
        CGFloat yDist = end.y - start.y;
        distance = sqrtf((xDist * xDist) +(yDist * yDist));
        return  distance;
    }
    View Code

        利用Pinch实现双指控制图片的缩放,关键点在于,如何判断是放大还是缩小,放大或者缩小的比例又是多少。这是数学上的问题了

       当然了,这只是其中一种缩放比例的方法,网上还有很多别的方法。

    2、rotation手势的响应:

    -(void)handleRotationRecognizer:(id)sender
    {
        UIRotationGestureRecognizer *ges = (UIRotationGestureRecognizer *)sender;
        if ([ges state] == UIGestureRecognizerStateBegan || [ges state] == UIGestureRecognizerStateChanged) {
            [ges view].transform = CGAffineTransformRotate([[ges view] transform], [ges rotation]);
            // rotate = [ges rotation];
            [ges setRotation:0];
        }    
    }
    View Code

    3、tap手势的响应

    -(void)handleTapGesture:( UITapGestureRecognizer *)tapRecognizer
    {
        int tapCount = tapRecognizer.numberOfTapsRequired;//记录点击次数
        // 先取消任何操作???????这句话存在的意义????????????????????????
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
        switch (tapCount){
            case 1:
                [self performSelector:@selector(handleSingleTap) withObject:nil afterDelay:0.22];
                break;
            case 2:
               [self performSelector:@selector(handleDoubleTap:) withObject:nil afterDelay:0.22];
                break;
        }
    }
    View Code

    4、longPressed手势的响应:(这个在定义手势的时候,加上了longPressRecognizer.minimumPressDuration = 1; //长按1秒后触发事件,默认是0.5s)

    这个响应没有什么好写的,看功能而异。

    5、Pan手势的响应:(以较快的速度拖放后view有滑行的效果),关键在:监视手势是否结束、监视触摸的速度

    - (void) handlePanRecognizer:(id)sender
    {
        NSLog(@"handlePanRecognizer called");
        UIPanGestureRecognizer * ges = (UIPanGestureRecognizer *)sender;
        CGPoint translation = [ges translationInView:self.view];
        ges.view.center = CGPointMake(ges.view.center.x + translation.x,
                                             ges.view.center.y + translation.y);
        [ges setTranslation:CGPointZero inView:self.view];
        
        if (ges.state == UIGestureRecognizerStateEnded) {
            
            CGPoint velocity = [ges velocityInView:self.view];
            CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
            CGFloat slideMult = magnitude / 200;
            NSLog(@"magnitude: %f, slideMult: %f", magnitude, slideMult);
            
            float slideFactor = 0.1 * slideMult; // Increase for more of a slide
            CGPoint finalPoint = CGPointMake(ges.view.center.x + (velocity.x * slideFactor),
                                             ges.view.center.y + (velocity.y * slideFactor));
            finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width);
            finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height);
            
            [UIView animateWithDuration:slideFactor*2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                ges.view.center = finalPoint;
            } completion:nil];
        }    
    }
    View Code

    代码实现解析:
    1)计算速度向量的长度(估计大部分都忘了)这些知识了。
    2)如果速度向量小于200,那就会得到一个小于的小数,那么滑行会很短
    3)基于速度和速度因素计算一个终点
    4)确保终点不会跑出父View的边界
    5)使用UIView动画使view滑动到终点

    运行后,快速拖动图像view放开会看到view还会在原来的方向滑行一段路。

    6、Swipe手势的响应:

    swipe手势主要是用来检测移动方向的,有一个属性direction。

    二、如果同时在一个界面上的两个view上,都添加上手势响应?怎么同时触发两个响应了?

    手势之间是互斥的,如果你想同时触发两个view的手势,那么需要实现协议UIGestureRecognizerDelegate,

    @interface ViewController : UIViewController<UIGestureRecognizerDelegate>  
    @end 

     并在协议这个方法里返回YES。

    -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer  
    {  
        return YES;  


    把self作为代理设置给手势:
    panGestureRecognizer.delegate = self;  
    pinchGestureRecognizer.delegate = self;  
    rotateRecognizer.delegate = self; 

    这样可以同时拖动或旋转缩放两个view了。

    三、手势之间的拦截

    手势识别具有互斥性,比如单击和双击,如果它识别出一种手势,其后的手势将不再识别。

    所以对于关联手势,要做特殊处理以帮助程序甄别,应该把当前手势归结到哪一类手势里面。

    比如,单击和双击并存时,如果不做处理,它就只能发送出单击的消息。为了能够识别出双击手势,就需要做一个特殊处理逻辑,即先判断手势是否是双击,在双击失效的情况下作为单击手势处理。使用[A requireGestureRecognizerToFail:B]函数,它可以指定当A手势发生时,即便A已经滿足条件了,也不会立刻触发会等到指定的手势B确定失败之后才触发。

      

    把这两个手势分开定义,

    即分别定义singleTapRecognizer,doubleTapRecognizer,然后设置

    singleTapRecognizer.numberOfTapsRequired = 1;

    doubleTapRecognizer.numberOfTapsRequired  = 2;

    [singleRecognizer requireGestureRecognizerToFail:doubleRecognizer]; // 双击手势确定监测失败才会触发单击手势的相应操作

     这三句话缺一不可,如果没有设numberOfTapsRequired,即使加了最后一句话,依然不能响应双击事件;如果没加最后一句话,可以响应双击事件,但每次双击时,会触发两次单击事件和一次双击事件,这些显然都不是我们想看到的。

     

    四、iphone操作手势的大概种类

    1.点击(Tap)
    点击作为最常用手势,用于按下或选择一个控件或条目(类似于普通的鼠标点击)、

    2.拖动(Drag)
    拖动用于实现一些页面的滚动,以及对控件的移动功能。

    3.滑动(Flick)
    滑动用于实现页面的快速滚动和翻页的功能。

    4.横扫(Swipe)
    横扫手势用于激活列表项的快捷操作菜单

    5.双击(Double Tap)
    双击放大并居中显示图片,或恢复原大小(如果当前已经放大)。同时,双击能够激活针对文字编辑菜单。

    6.放大(Pinch open)
    放大手势可以实现以下功能:打开订阅源,打开文章的详情。在照片查看的时候,放大手势也可实现放大图片的功能。

    7.缩小(Pinch close)
    缩小手势,可以实现与放大手势相反且对应的功能的功能:关闭订阅源退出到首页,关闭文章退出至索引页。在照片查看的时候,缩小手势也可实现缩小图片的功能。

    8.长按(Touch &Hold)
    在我的订阅页,长按订阅源将自动进入编辑模式,同时选中手指当前按下的订阅源。这时可直接拖动订阅源移动位置。
    针对文字长按,将出现放大镜辅助功能。松开后,则出现编辑菜单。
    针对图片长按,将出现编辑菜单。

    9.摇晃(Shake)
    摇晃手势,将出现撤销与重做菜单。主要是针对用户文本输入的。

    五、自定义手势

    请参考:http://www.cocoachina.com/newbie/basic/2013/0501/6108.html

    本篇博客非本人完全原创,参考了:http://blog.csdn.net/likendsl/article/details/7554150和上面共两篇博客

  • 相关阅读:
    Civil 3D 二次开发 创建Civil 3D 对象—— 01 —— 创建几何空间点
    Civil 3D 二次开发 创建Civil 3D 对象—— 00 ——
    Civil 3D 二次开发 创建AutoCAD对象—— 01 —— 创建直线
    Civil 3D 二次开发 新建CLR项目出现错误C2143
    Civil 3D 二次开发 创建AutoCAD对象—— 00 ——
    了解AutoCAD对象层次结构 —— 6 ——块表记录
    datepicker97使用
    使用angular 外接 templateUrl,使用ng-include
    angularJs 遮罩
    网上找的有关css兼容问题
  • 原文地址:https://www.cnblogs.com/wyqfighting/p/3189822.html
Copyright © 2011-2022 走看看