触摸手势以及图形变换(UIGestureRecognizer, CGAffineTransform)

概要

   本章主要学习了IOS开发中的触摸手势以及图形变换的知识,其中手势包括单击、双击、长按、拖动、滑动、缩放、旋转,图形变化主要使用放射矩阵的平移、缩放和旋转。

   使用手势时应该注意手势是指定到特定的视图(UIView)上的,因此一个手势只能对应一个视图(手势里面的view属性可获取其所所对应的视图),而一个View可以添加多个手势。同时,因为有的手势之间有冲突的,比如单击和双击,滑动和拖动。针对这种情形需要使用手势的依赖性特性做出区分,改特性要求特定手势失败后才触发该手势。

   仿射矩阵变化应该注意到是通过视图的变化而达到显示效果的,同时还要注意到UIKit坐标和绘图坐标之间的差异。

结果展示

技术分享

流程概要

1.手势是针对特定视图的,所以在学习过程中我都是在一个视图类里面做实验的,该类是一个UIView的子类。

2.IOS的手势分为以下几个,其分别对应一个类:

    一个滑动手势的对象只支持一个方向,默认是右滑,如果想要支持四个方向,那就需要添加四个滑动手势的对象,同时通过属性direction指定。

3.添加手势到视图可使用下述模板代码

/** 滑动 */
_swipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(onSwipeGesture:)];
/** 设置手滑方向,只支持一个方向,默认是右滑 */
_swipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionUp;
[_imageView addGestureRecognizer:_swipeGestureRecognizer];

注意要使的视图支持手势对象,需要启动支持手势属性,将属性userInteractionEnabled设为YES。

4.图形变化中注意到有CGAffineTransformMakeRotation和CGAffineTransformRotate类似的成对出现,其中前者有Make表示新建一个默认的矩阵,然后设置属性,而后者则是在指定的矩阵上添加属性特征,所以大部分使用类似于后者的仿射变换函数。使用例子如下

/** 设置(之前设置的其他矩阵属性重新变为默认值)矩阵 */
//CGAffineTransform t = CGAffineTransformMakeRotation(angle);
    
/** 修改矩阵旋转属性 */
CGAffineTransform t = CGAffineTransformRotate(_imageView.transform, angle);
self.imageView.transform = t;

5.缩放手势(UIPinchGestureRecognizer)对象有属性scale,该属性表示缩放系数,所以在响应缩放手势的方法中可直接读取该属性设置缩放,不过使用完毕后注意将该值重置为1,如:

recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
recognizer.scale = 1;
6.旋转手势(UIRotationGestureRecognizer)对象有属性rotation,该属性表示旋转属性值,所以在响应旋转手势的方法中可直接使用该属性值设置视图的旋转,注意重置0,如

ecognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation);
recognizer.rotation = 0;
7.拖动手势(UIPanGestureRecognizer)对象通过方法translationInView获取拖动后的参数,使用例子如下

CGPoint translation = [recognizer translationInView:self];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,                                         recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointZero inView:self];

主要代码

视图类文件

//
//  PickView.m
//  Gesture
//
//  Created by arbboter on 14/12/19.
//  Copyright (c) 2014年 arbboter. All rights reserved.
//

#import "PickView.h"

@interface PickView ()

@property (nonatomic, retain) UIImageView* imageView;

@property (nonatomic, retain) UITapGestureRecognizer* tapSingleGestureRecognizer;
@property (nonatomic, retain) UITapGestureRecognizer* tapDoubleGestureRecognizer;
@property (nonatomic, retain) UIPinchGestureRecognizer* pinchGestureRecognizer;
@property (nonatomic, retain) UIRotationGestureRecognizer* rotationGestureRecognizer;
@property (nonatomic, retain) UISwipeGestureRecognizer* swipeGestureRecognizer;
@property (nonatomic, retain) UIPanGestureRecognizer* panGestureRecognizer;
@property (nonatomic, retain) UILongPressGestureRecognizer* longPressGestureRecognizer;

@end

@implementation PickView

-(void) viewImageNamed:(NSString*)imageName
{
    self.layer.borderWidth = 1;
    _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.frame.size.height/4, 200, 200)];
    _imageView.image = [UIImage imageNamed:imageName];
    _imageView.contentMode = UIViewContentModeScaleAspectFit;
    
    /**
     *
     UIViewContentModeScaleToFill,     // 默认缩放方式,上下左右填充 [部分]
     UIViewContentModeScaleAspectFit,  // 等比例缩放,一般效果是按照小的方向缩放 [全图]
     UIViewContentModeScaleAspectFill, // 等比例缩放,一般效果是按照小的方向缩放(会出现剪裁效果)[部分]
     UIViewContentModeRedraw,          // 视图的bounds变化时重绘
     UIViewContentModeCenter,          // 放在视图的bounds的中间,保持等比例 [部分]
     UIViewContentModeTop,
     UIViewContentModeBottom,
     UIViewContentModeLeft,
     UIViewContentModeRight,
     UIViewContentModeTopLeft,
     UIViewContentModeTopRight,
     UIViewContentModeBottomLeft,
     UIViewContentModeBottomRight
     */
    
    [self addSubview:_imageView];
    
    /** 单击 */
    _tapSingleGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapSingleGesture:)];
    [_tapSingleGestureRecognizer setNumberOfTapsRequired:1];
    [_imageView addGestureRecognizer:_tapSingleGestureRecognizer];
    
    /** 双击 */
    _tapDoubleGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapDoubleGesture:)];
    [_tapDoubleGestureRecognizer setNumberOfTapsRequired:2];
    [_imageView addGestureRecognizer:_tapDoubleGestureRecognizer];
    
    /** 因为双击和单击存在冲突,所以需要设定没有双击才识别为单击 */
    [_tapSingleGestureRecognizer requireGestureRecognizerToFail:_tapDoubleGestureRecognizer];
    
    /** 缩放 */
    _pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(onPinchGesture:)];
    [_imageView addGestureRecognizer:_pinchGestureRecognizer];
    
    /** 旋转 */
    _rotationGestureRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(onRotationGesture:)];
    [_imageView addGestureRecognizer:_rotationGestureRecognizer];
    
    /** 滑动 */
    _swipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(onSwipeGesture:)];
    /** 设置手滑方向,只支持一个方向,默认是右滑 */
    _swipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionUp;
    [_imageView addGestureRecognizer:_swipeGestureRecognizer];
    
    /** 拖动 */
    _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onPanGesture:)];
    [_imageView addGestureRecognizer:_panGestureRecognizer];
    
    /** 拖动和滑动有冲突,有限响应滑动 */
    [_panGestureRecognizer requireGestureRecognizerToFail:_swipeGestureRecognizer];
    
    /** 长按 */
    _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPressGesture:)];
    [_imageView addGestureRecognizer:_longPressGestureRecognizer];
    
    /** 图片视图启动触摸交互 */
    _imageView.userInteractionEnabled = YES;
}

-(void) viewRotate:(CGFloat)angle
{
    /** 设置(之前设置的其他矩阵属性重新变为默认值)矩阵 */
    //CGAffineTransform t = CGAffineTransformMakeRotation(angle);
    
    /** 修改矩阵旋转属性 */
    CGAffineTransform t = CGAffineTransformRotate(_imageView.transform, angle);
    self.imageView.transform = t;
}

-(void) viewTranslationX:(CGFloat)x Y:(CGFloat)y
{
    /** 修改矩阵平移属性 */
    CGAffineTransform t = CGAffineTransformTranslate(_imageView.transform, x, y);
    self.imageView.transform = t;
}

-(void) viewScaleX:(CGFloat)x Y:(CGFloat)y
{
    /** 修改矩阵缩放属性 */
    CGAffineTransform t = CGAffineTransformScale(_imageView.transform, x, y);
    self.imageView.transform = t;
}

#pragma 响应手势
- (void)onTapSingleGesture:(UITapGestureRecognizer*) recognizer
{
    NSLog(@"%s", __FUNCTION__);
    /** do nothing */
}
- (void)onTapDoubleGesture:(UITapGestureRecognizer*) recognizer
{
    NSLog(@"%s", __FUNCTION__);
    
    
    CGFloat x = self.superview.frame.size.width/_imageView.frame.size.width;
    CGFloat y = self.superview.frame.size.height/_imageView.frame.size.height;
    
    [self viewTranslationX:self.superview.frame.size.width-self.frame.size.width Y:0];
    
    NSLog(@"%.2f %.2f", _imageView.center.x, _imageView.center.y);
    // 缩放
    if(x==1)
    {
        [self viewScaleX:0.5 Y:0.5];
    }
    // 放大
    else
    {
        x = x > y ? y : x;
        [self viewScaleX:x Y:x];
    }
    
    /** 左边界对齐 */
    _imageView.center = CGPointMake(_imageView.frame.size.width/2, _imageView.frame.size.height/2 + self.superview.frame.size.height/4);
    x = _imageView.frame.origin.x;
    
    [self viewTranslationX:-x Y:0];
}

- (void)onPinchGesture:(UIPinchGestureRecognizer*) recognizer
{
    NSLog(@"%s", __FUNCTION__);
    
    /** 缩放图片 */
    recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
    recognizer.scale = 1;
}

- (void)onRotationGesture:(UIRotationGestureRecognizer*) recognizer
{
    NSLog(@"%s", __FUNCTION__);
    
    /** 旋转 */
    recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation);
    recognizer.rotation = 0;
}

- (void)onSwipeGesture:(UISwipeGestureRecognizer*) recognizer
{
    NSLog(@"%s", __FUNCTION__);
    
    /** 上滑修改父视图背景色 */
    if(recognizer.direction == UISwipeGestureRecognizerDirectionUp)
    {
        CGFloat color[3] = {0};
        
        color[0] = (arc4random()%50 + 1)/100.0;
        color[1] = (arc4random()%50 + 1)/100.0;
        color[2] = 1 - color[0] - color[1];
        
        self.superview.backgroundColor = [UIColor colorWithRed:color[0] green:color[1] blue:color[2] alpha:1.0];
    }
}

- (void)onPanGesture:(UIPanGestureRecognizer*) recognizer
{
    NSLog(@"%s", __FUNCTION__);
    
    /** 拖动图片 */
    CGPoint translation = [recognizer translationInView:self];
    recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
                                         recognizer.view.center.y + translation.y);
    [recognizer setTranslation:CGPointZero inView:self];
}

- (void)onLongPressGesture:(UILongPressGestureRecognizer*) recognizer
{
    NSLog(@"%s", __FUNCTION__);
    
    /** 防止同一时间多次调用 */
    if(recognizer.state == UIGestureRecognizerStateBegan)
    {
        /** 弹出编辑选项 */
        UIActionSheet* action = [[UIActionSheet alloc] initWithTitle:@"Edit Options" delegate:nil cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Show details" otherButtonTitles:@"Delete", @"Modify", @"Send", nil];
        
        [action showInView:self];
        [action release];
    }
    
}


-(void) dealloc
{
    [_imageView release];
    [self removeGestureRecognizer:_tapSingleGestureRecognizer];
    [self removeGestureRecognizer:_tapDoubleGestureRecognizer];
    [self removeGestureRecognizer:_pinchGestureRecognizer];
    [self removeGestureRecognizer:_rotationGestureRecognizer];
    [self removeGestureRecognizer:_swipeGestureRecognizer];
    [self removeGestureRecognizer:_panGestureRecognizer];
    [self removeGestureRecognizer:_longPressGestureRecognizer];
    
    [_tapSingleGestureRecognizer release];
    [_tapDoubleGestureRecognizer release];
    [_pinchGestureRecognizer release];
    [_rotationGestureRecognizer release];
    [_swipeGestureRecognizer release];
    [_panGestureRecognizer release];
    [_longPressGestureRecognizer release];

    [super dealloc];
}

@end


项目工程




郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。