触摸手势以及图形变换(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

项目工程

时间: 2024-11-03 23:51:31

触摸手势以及图形变换(UIGestureRecognizer, CGAffineTransform)的相关文章

Qt for android触摸手势事件QGestureEvent

在触摸设备上可以使用Qt的手势事件 要激活手势事件,需要执行以下操作: 第一步,为QWidget控件注册手势事件 QList<Qt::GestureType> gestures; gestures << Qt::PanGesture; gestures << Qt::PinchGesture; gestures << Qt::SwipeGesture; gestures << Qt::TapGesture; gestures << Q

Android 触摸手势基础 官方文档概览2

Android 触摸手势基础 官方文档概览 触摸手势检测基础 手势检测一般包含两个阶段: 1.获取touch事件数据 2.解析这些数据,看它们是否满足你的应用所支持的某种手势. 相关API: MotionEvent 兼容版的: MotionEventCompat  (Note that MotionEventCompat is not a replacement for the MotionEvent class. Rather, it provides static utility metho

Android最佳实践之触摸手势

普通手势 参考地址:http://developer.android.com/training/gestures/detector.html#data 当用户一根或多根手指在屏幕上运动的时候,就开始产生了手势事件,我们用onTouchEvent()回调方法来处理. 为Activity 或View捕捉触摸事件 使用getActionMasked()来提取event中的action. public class MainActivity extends Activity { ... // This e

Quo JS多种触摸手势轻量级JavaScript库【唯美巷转载】

Quo JS是一个轻量级模块化.面向对象的JavaScript库,定义了多种触摸手势,可以用于移动Web开发中简化HTML文件遍历.事件处理及Ajax交互等,让开发者轻松编写出高效的跨浏览器代码. Quo JS介绍 Quo JS旨在简化你的移动开发项目的代码量,针对当前的移动设备优化代码运行,支持单点.多点.滑动.按住等多种手势的操作. 专为移动 为了改变你的目标,编写JavaScript的方式:一个好的API库5-6k gzip压缩过的所以你可以集中精力处理最基本的东西做苦力的工作.开源的MI

Android 触摸手势基础 官方文档概览

触摸手势检测基础 手势检测一般包含两个阶段: 1.获取touch事件数据 2.解析这些数据,看它们是否满足你的应用所支持的某种手势. 相关API: MotionEvent 兼容版的: MotionEventCompat  (Note that MotionEventCompat is not a replacement for the MotionEvent class. Rather, it provides static utility methods to which you pass y

支持元素惯性拖放和多点触摸手势的js插件

interact.js是一款支持元素惯性拖放和多点触摸手势的js插件.该插件支持在桌面设备和移动手机设备中拖放元素,拖动结束时带有惯性效果.并且支持移动设备的多点触摸手势.它的特点有: 带惯性和吸附效果 支持多元互动 跨浏览器和设备,支持桌面和移动版本的Chrome, Firefox 和 Opera浏览器以及IE8+浏览器 可以和SVG元素相互作用 轻量级,无任何外部依赖 除非要支持IE8或修改鼠标样式,否则不用修改任何DOM元素 效果演示:http://www.htmleaf.com/Demo

错误总结之播放器(vitamio)音量实体键与触摸手势控制,音量调节冲突

这个可是独家心得:经过几天的网上资料查询未果,在群里遇到一同行.然后让他帮我看了看,最终解决了该冲突.此时,谨以此来感谢那位同僚的热情帮助: 说说这个问题吧: 目前我在做一款影视方面的项目,在该项目中肯定是要用到视频播放这一块,视频播放是引用了vitamio类库,播放页面使用的是SurfaceView控件.然后在视频播放的期间,有这些要求:手势滑动调节音量.当我费劲千辛万苦搞定之后,没有想到却遇到了按音量实体键的时候播放页面退出的冲突问题.那么怎么解决该问题呢?很简单,几行代码的事情. 返回键监

浅谈android中图片处理之图形变换特效Matrix(四)

今天,我们就来谈下android中图片的变形的特效,在上讲博客中我们谈到android中图片中的色彩特效来实现的.改变它的颜色主要通过ColorMatrix类来实现. 现在今天所讲的图片变形的特效主要就是通过Matrix类来实现,我们通过上篇博客知道,改变色彩特效,主要是通过ColorMatrxi矩阵的系数,以及每个像素点上所对应的颜色偏移量.而今天的图形变换与那个也是非常的类似.它是一个3*3矩阵,而颜色矩阵则是一个4*5的矩阵.在这个3*3矩阵中则表述出了每个像素点的XY坐标信息.然后通过修

二维图形变换

5.1二维图形变化 一.向量 是具有长度和方向的实体 二.特殊的线性组合 (1)仿射组合 (2)凸组合(对仿射组合加以更多的限制) 三.向量的点积和叉积 (1)点积 两个向量夹角的余弦值等于两个单位向量的点积 (2)叉积 两个向量的叉积是另一个三维向量,且与两个向量均正交 利用叉积求平面的法向量,三点可确定一个平面 5.2 图形坐标系 1.世界坐标系 是一个公共坐标系,是现实中物体或场景的统一参考系 2.建模坐标系 又称局部坐标系,每个物体有自己的局部中心和坐标系 3.观察坐标系 从观察者的角度