实战1.2-利用手势识别器,实现视图的手势控制
title: 实战1.2-利用手势识别器,实现视图的手势控制
知识预备
- 什么是仿射变换?
从视觉效果上来理解,仿射变换是通过一系列原子变换复合而来的变换。包括:平移(Translation)、缩放(Scale)、翻转(Flip)、旋转(Rotation)和错切(Shear)(图像的错切实际上是平面景物在投影平面上的非垂直投影)。
- iOS 视图的 frame 和 bounds 属性的区别
frame 描述了该视图在父视图坐标系统中的位置和大小,其参照点是父视图的坐标系统。
bounds 描述了该视图在本地坐标系统中的位置和大小,其参照点是该视图自己的坐标系统。
如果还有疑惑,可以点击下方链接,这篇博文确切地解释了区别所在。
iOS 视图的 frame 和 bounds 属性的区别
3.UIGestureRecognizerState 的参数值(状态)
-
UIGestureRecognizerStatePossible : 手势识别器还没有识别出手势,但是可能正在估算触摸事件(touches event),还处在判断阶段。这个状态是手势识别器的默认状态。
-
UIGestureRecognizerStateBegan : 手势识别器已经接收到了一系列触摸并且识别出了它属于哪个手势。响应方法在下一个运行周期被调用。
-
UIGestureRecognizerStateChanged : 手势识别器已经接收到了一系列触摸并且识别出手势发生了改变。响应方法在下一个运行周期被调用。
-
UIGestureRecognizerStateEnded : 手势识别器已经接收到了一系列触摸并且识别出手势刚刚结束。响应方法在下一个运行周期被调用,并且把手势状态的值重新置为 UIGestureRecognizerStatePossible。
-
UIGestureRecognizerStateCancelled : 手势识别器已经接收到了一系列触摸并且识别出手势突然中断。响应方法在下一个运行周期被调用,并且把手势状态的值重新置为 UIGestureRecognizerStatePossible。
-
UIGestureRecognizerStateFailed : 手势识别器已经接收到了一系列多点触控,但是与识别器认识的手势匹配失败(识别不出来)。无响应方法。把手势状态的值重新置为 UIGestureRecognizerStatePossible。
-
UIGestureRecognizerStateRecognized : 手势识别器已经接收到了一系列多点触控,并且识别器识别出该手势。响应方法在下一个运行周期被调用,并且把手势状态的值重新置为 UIGestureRecognizerStatePossible。
实战
-
创建工程步骤请参照 实战1中的前几步。
-
在工程中创建一个 MyImageView 视图类,继承自 UIImageView。
-
首先为我们创建的视图类进行初始化方法的编写,在 MyImageView.m 文件中:
static int count; @implementation MyImageView { CGPoint previousLocation; UIPanGestureRecognizer *panGestureRecognizer; } #pragma mark - initialization - (id) initWithImage:(UIImage *)image { self = [super initWithImage:image]; if (self) { self.userInteractionEnabled = YES; // 在视图被初始化的过程中,创建一个 拖动手势识别器 // 应用 target-action 模式,以该类为目标对象,如果手势被触发,handlePan: 方法会被调用 panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; // 该类的实例对象能够被 拖动手势识别器 所识别 self.gestureRecognizers = @[panGestureRecognizer]; } return self; } - (id) init { // 图片文件的名称为 blue.png return [self initWithImage:[UIImage imageNamed:@"blue"]]; } #pragma mark - touches mothods are called // 当该类的实例对象被触碰的时候,该方法会被触发 - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.superview bringSubviewToFront:self]; // 视图中心点 previousLocation = self.center; } #pragma mark - selector handlePan: - (void) handlePan:(UIPanGestureRecognizer *) gestureRecognizer { // print 该方法的运行次数 NSLog(@"%i", ++count); // 根据视图的仿射变换来获取偏移量 CGPoint translation = [gestureRecognizer translationInView:self.superview]; // 重置视图中心点 self.center = CGPointMake(previousLocation.x + translation.x, previousLocation.y + translation.y); }
-
在 ViewController.h 文件中声明属性:
@class MyImageView; @interface ViewController : UIViewController @property (nonatomic, strong) MyImageView *myImageView;
-
在 ViewController.m 文件中导入头文件(#import "MyImageView.h")并写入代码:
- (void)viewDidLoad { [super viewDidLoad]; // 创建类实例并且添加视图 _myImageView = [[MyImageView alloc] initWithImage:[UIImage imageNamed:@"blue"]]; [self.view addSubview:_myImageView]; }
- 运行结果: 视图能够响应拖动手势,在屏幕上被拖动。控制台显示结果标明, handlePan: 方法在拖动手势进行过程中,一直都在被调用,直至手势停止。 console
总结:
** 为了让自定义视图能够响应手势,我们在创建并且初始化视图类实例的时候,就应该创建响应的手势识别器及其会响应的方法,当手势在进行过程中时,响应方法被反复调用,直至手势停止。为了让视图能够跟随手势移动,我们只需根据视图先前的中心位置和被拖动以后的偏移位置来重新设定视图的中心位置即可。
**