iOS手势 总结归纳

来源:互联网 发布:中国证券市场数据库 编辑:程序博客网 时间:2024/05/18 01:04

最近需要把项目中的播放器中的手势层重构,顺便总结了iOS的手势相关的代码。  

1.单击双击共存的代码

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap)];
//双击
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap)];
[doubleTap setNumberOfTapsRequired:2];
[self.view addGestureRecognizer:singleTap];
[self.view addGestureRecognizer:doubleTap];

[singleTap requireGestureRecognizerToFail:doubleTap];

2.滑动相关手势

UISwipeGestureRecognizer * swipeGes = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(recog)];

[swipeGes setDirection:UISwipeGestureRecognizerDirectionUp];

[self.view addGestureRecognizer:swipeGes];

UISwipeGestureRecognizer通常用作滑动,优点是代码简单,系统自动判断滑动方向。缺点是不能持续触发,有时不方便使用。

 通常,有时也用UIPanGestureRecognizer实现滑动手势,好处是能随着手指在屏幕上移动而持续触发滑动的相关事件,在事件中持续获得滑动的相应参数,可以实现连续控制。由于比较复杂,放在最后的demo 中

3.其他手势

其他手势不在一一总结,简述如下:
UIPinchGestureRecognizer(捏合)
UIRotationGestureRecognizer(旋转)
UILongPressGestureRecognizer(长按)

长按很简单,捏合和旋转暂时没有用过,最后补充一段简单的代码。


PS1:

以下代码是一段视频播放器中手势代码。主要实现了单击显示控制视图,双击暂停/播放,左侧上下滑动调节亮度,右侧上下滑动调节音量,左右滑动控制播放进度

ControlView中如下:

①三个全局变量的手势,其中,_pan处理所有的滑动,待会仔细介绍。另外俩分别处理单击,双击。还有三个变量是控制触发频率的全局变量,稍后介绍。

    CGPoint _beginTouchPoint;
    SlideDirect _direct;
    NSInteger _currentDegree;   

    UIPanGestureRecognizer * _panGes;
    UITapGestureRecognizer * _singleTapGes;
    UITapGestureRecognizer * _doubleTapGes;

②初始化这三个手势并添加到视图中。单击双击比较简单,主要是滑动模块,需要自己判断滑动方向,距离大小

- (void)initGesture{
    
     _singleTapGes = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapReceived:)];

    //双击
    _doubleTapGes = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapReceived:)];
    [_doubleTapGes setNumberOfTapsRequired:2];
    [self addGestureRecognizer:_singleTapGes];
    [self addGestureRecognizer:_doubleTapGes];
    
    [_singleTapGes requireGestureRecognizerToFail:_doubleTapGes];
    
    _panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    [self addGestureRecognizer:_panGes];
    _currentDegree = 1;
}

触发的时间

- (void)handlePan:(UIPanGestureRecognizer *)sender
{
    switch (sender.state) {
        case UIGestureRecognizerStateBegan:
        {
            //开始滑动,则记录下来作为起始点
            _beginTouchPoint = [sender locationInView:sender.view];
            break;
            return;
        }
        case UIGestureRecognizerStateChanged:
        {
            //滑动持续进行中。。。
            //获取当前点的坐标
            CGPoint newPoint = [sender locationInView:sender.view];
            
            if (_direct == SlideDirectNone ) {
                //当前没有滑动方向,则给其赋值
                CGFloat degree = fabs((newPoint.y - _beginTouchPoint.y) / (newPoint.x - _beginTouchPoint.x));
                
                //degree表示当前点和起始点之间连线的斜率。防止误判,只有斜率过高/过低,才能判定滑动方向,进而判断是向上下左右滑动。
                if (degree > 1.5f) {
                    _direct = newPoint.y < _beginTouchPoint.y ? SlideDirectUp : SlideDirectDown;
                }
                else if (degree < 0.6){
                    _direct = newPoint.x > _beginTouchPoint.x ? SlideDirectRight : SlideDirectLeft;
                }
            }
            if (_direct == SlideDirectNone) {
                //仍然没有方向,说明之前判断滑动方向时没有达到临界值,则不认为是正常的滑动,则此次跳出;
                break;
            }
            
            //已判断出当前方向,则进行方法的调用
            switch (_direct) {
                case SlideDirectUp:
                {
                    CGFloat degree = _beginTouchPoint.y - newPoint.y;
                    if (_beginTouchPoint.x < (kScreenWidth / 2.0)) {
                        //左侧,调节亮度
                        [self gestureSlideGes:GesTypeBrightnessUp degre:degree];
                    }else{
                        //右侧,调节音量
                        [self gestureSlideGes:GesTypeVoiceUp degre:degree];
                    }
                }
                    break;
                case SlideDirectDown:
                {
                    CGFloat degree = newPoint.y - _beginTouchPoint.y;
                    if (_beginTouchPoint.x < (kScreenWidth / 2.0)) {
                        //左侧,调节亮度
                        [self gestureSlideGes:GesTypeBrightnessDown degre:degree];
                    }else{
                        //右侧,调节音量
                        [self gestureSlideGes:GesTypeVoiceDown degre:degree];
                    }
                }
                    break;
                case SlideDirectLeft:
                {
                    //在滑动过程中触发左滑/右滑,则只触发开始滑动,
                    CGFloat degree = newPoint.x - _beginTouchPoint.x;
                    [self gestureSlideGes:GesTypeBeginSlide degre:degree];
                }
                    break;
                case SlideDirectRight:
                {
                    CGFloat degree = newPoint.x - _beginTouchPoint.x;
                    [self gestureSlideGes:GesTypeBeginSlide degre:degree];
                }
                    break;
                    
                default:
                    break;
            }
        }
            break;
        case UIGestureRecognizerStateEnded:
        {
            if (_direct == SlideDirectRight || _direct == SlideDirectLeft) {
                //如果是左右滑动,抬起时需要触发特殊事件,上下滑则不关心最后的抬起
                CGPoint newPoint = [sender locationInView:sender.view];
                CGFloat degree = newPoint.x - _beginTouchPoint.x;
                [self gestureSlideGes:_direct == SlideDirectLeft ? GesTypeBackward : GesTypeForward degre:degree];
            }
            
            _direct = SlideDirectNone;
            _currentDegree = 1;
        }
            break;
            
        default:
            break;
    }
}

- (void)gestureSlideGes:(GesType)ges degre:(CGFloat )degre{
    if (fabs(degre) < _currentDegree * 30.0f && ges != GesTypeForward && ges != GesTypeBackward) {
        //如果是普通上下滑动,则是调节亮度或者音量。
        //因为pan手势触发太过于频繁,不可能每次都触发增加/减少亮度/音量,
        //因为这两个总共就是20个档左右,太过敏感。故只有滑动距离达到30的整数倍时才能正常触发
        return;
    }
    _currentDegree ++;
    if ([self.baseDelegate respondsToSelector:@selector(recogGes:degree:)]) {
        [self.baseDelegate recogGes:ges degree:degre];
    }
}


补充:因为视频播放解码比较慢,不能做到随着左右滑动实时将对应的视频解码出来,只能在滑动中调节进度条,等到手指抬起时将对应进度条的视频解码出来


PS2:

手势的状态,

typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
    UIGestureRecognizerStatePossible,     // 尚未识别是何种手势操作(但可能已经触发了触摸事件),默认状态
    UIGestureRecognizerStateBegan,        // 手势已经开始,此时已经被识别,但是这个过程中可能发生变化,手势操作尚未完成
    UIGestureRecognizerStateChanged,    // 手势状态发生转变
    UIGestureRecognizerStateEnded,        // 手势识别操作完成(此时已经松开手指)
    UIGestureRecognizerStateCancelled,  // 手势被取消,恢复到默认状态
    UIGestureRecognizerStateFailed,        // 手势识别失败,恢复到默认状态
    UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded // 手势识别完成,同UIGestureRecognizerStateEnded
};

0 0
原创粉丝点击