1 使用点击手势实现单击和双击手势
1.1 问题
UITapGestureRecognizer点击手势,通常用于单击和双击某个视图。本案例使用UITapGestureRecognizer点击手势实现单击和双击,如图-1、图-2所示:
图-1
图-2
1.2 方案
首先创建Xcode项目,在Storyboard中拖放一个ImageView控件和Label控件,在右边栏设置好相关属性,此时注意将ImageView的用户交互功能打开,否则无法识别手势。
其次将ImageView和Label控件关联成TRViewController的属性imageView和label。在TRViewController类中的viewDidLoad方法中创建一个UITapGestureRecognizer手势tapGR,使用initWithTarget: action:方法进行初始化并添加事件方法tap:。
将tap手势的numberOfTapsRequired属性设置为1,表示点击一下的意思即单击。最后将手势添加到view中,实现方法tap:点击view则在label上显示“view被点击了一下”。
然后在TRViewController类中的viewDidLoad方法中创建一个UITapGestureRecognizer手势doubleTap,使用initWithTarget: action:方法进行初始化并添加事件方法doubleTap:。
将doubleTap手势的numberOfTapsRequired属性设置为2,表示点击两下的意思即双击。最后将手势添加到imageView中,实现方法doubletap:点击imageView则在label上显示“imageView被点击了两下”。
1.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目搭建界面
首先创建Xcode项目,在Storyboard中拖放一个ImageView控件和Label控件,在右边栏设置好相关属性,此时注意将ImageView的用户交互功能打开,否则无法识别手势,如图-3所示:
图-3
步骤二:创建单击手势,添加到界面
首先将ImageView和Label控件关联成TRViewController的属性imageView和label,代码如下所示:
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet UIImageView *imageView;
- @property (weak, nonatomic) IBOutlet UILabel *label;
- @end
然后在TRViewController类中的viewDidLoad方法中创建一个UITapGestureRecognizer手势tapGR,使用initWithTarget: action:方法进行初始化并添加事件方法tap:,代码如下所示:
- UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
将tap手势的numberOfTapsRequired属性设置为1,表示点击一下的意思即单击。最后将手势添加到view中,代码如下所示:
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- //创建手势对象
- UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
- //设置相关属性
- tapGR.numberOfTapsRequired = 1;
- tapGR.numberOfTouchesRequired = 1;
- //将手势对象加入到需要识别手势的视图
- [self.view addGestureRecognizer:tapGR];
- }
最后实现方法tap:,当点击view则在label上显示“view被点击了一下”,代码如下所示:
- - (void)tap:(UITapGestureRecognizer *)gr
- {
- self.label.text = @"view被点击了一下";
- }
步骤三:创建双击手势,添加到界面
然后在TRViewController类中的viewDidLoad方法中创建一个UITapGestureRecognizer手势doubleTap,使用initWithTarget: action:方法进行初始化并添加事件方法doubleTap:,代码如下所示:
- UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(doubleTap:)];
将doubleTap手势的numberOfTapsRequired属性设置为2,表示点击两下的意思即双击。最后将手势添加到view中,代码如下所示:
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
- tapGR.numberOfTapsRequired = 1;
- tapGR.numberOfTouchesRequired = 1;
- [self.view addGestureRecognizer:tapGR];
- UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(doubleTap:)];
- [doubleTap setNumberOfTapsRequired:2];
- [self.imageView addGestureRecognizer:doubleTap];
- }
最后实现方法doubleap:,当点击imageView则在label上显示“imageView被点击了两下”,代码如下所示:
- -(void)doubleTap:(UITapGestureRecognizer*)gr {
- self.label.text = @"imageView被点击了两下";
- }
1.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet UIImageView *imageView;
- @property (weak, nonatomic) IBOutlet UILabel *label;
- @end
- @implementation TRViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- //1. 创建手势对象
- UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
- //2. 设置相关属性
- tapGR.numberOfTapsRequired = 1;
- tapGR.numberOfTouchesRequired = 1;
- //3. 将手势对象加入到需要识别手势的视图
- [self.view addGestureRecognizer:tapGR];
- UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(doubleTap:)];
- [doubleTap setNumberOfTapsRequired:2];
- [self.imageView addGestureRecognizer:doubleTap];
- }
- - (void)tap:(UITapGestureRecognizer *)gr
- {
- self.label.text = @"view被点击了一下";
- }
- -(void)doubleTap:(UITapGestureRecognizer*)gr {
- self.label.text = @"imageView被点击了两下";
- }
- @end
2 使用轻扫手势切换两张图片
2.1 问题
UISwipeGestureRecognizer轻扫手势,通常用于翻书、翻页、切换画面等效果。本案例将使用UISwipeGestureRecognizer轻扫手势实现两张图片的切换显示,如图-4、图-5所示:
图-4
图-5
2.2 方案
首先创建Xcode项目,在Storyboard中拖放两个和屏幕一样大小的ImageView控件,在屏幕上叠放在一起。
其次在TRViewController类中的viewDidLoad方法中创建一个UISwipeGestureRecognizer手势swipeGR,使用initWithTarget: action:方法进行初始化并添加事件方法swipe:。
将swipe手势的direction属性设置为左右,表示从右向左轻滑或者由左向右轻滑都可以触发手势的动作事件。然后将手势添加到self.view中。
最后将手势添加到view中,实现方法swipe:,当滑动图片则切换两个ImageView的显示顺序。
2.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目搭建界面
首先创建Xcode项目,在Storyboard中拖放两个和屏幕一样大小的ImageView控件,在屏幕上叠放在一起,如图-6所示:
图-6
步骤二:创建swipe手势,添加到界面
在TRViewController类中的viewDidLoad方法中创建一个UISwipeGestureRecognizer手势swipeGR,使用initWithTarget: action:方法进行初始化并添加事件方法swipe:,代码如下所示:
- UISwipeGestureRecognizer *swipeGR = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipe:)];
将swipe手势的direction属性设置为左右,表示从右向左轻滑或者由左向右轻滑都可以触发手势的动作事件,并将手势添加到self.view中,代码如下所示:
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UISwipeGestureRecognizer *swipeGR = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipe:)];
- swipeGR.direction = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight ;
- [self.view addGestureRecognizer:swipeGR];
- }
步骤三:实现事件方法swipe:
实现方法swipe:,当滑动图片则切换两个ImageView的显示顺序,代码如下所示:
- - (void)swipe:(UISwipeGestureRecognizer *)gr
- {
- [self.view exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
- NSLog(@"%@",self.view.subviews);
- }
2.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @implementation TRViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UISwipeGestureRecognizer *swipeGR = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipe:)];
- swipeGR.direction = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight ;
- [self.view addGestureRecognizer:swipeGR];
- }
- - (void)swipe:(UISwipeGestureRecognizer *)gr
- {
- [self.view exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
- NSLog(@"%@",self.view.subviews);
- }
- @end
3 使用缩放手势改变textView的显示状态和字体大小
3.1 问题
UIPinchGestureRecognizer缩放手势,通常用于缩放图片或视图,本案例使用UIPinchGestureRecognizer缩放手势实现改变textView的字体大小,当缩小速度足够快时则隐藏textView,如图-7所示:
图-7
3.2 方案
首先创建Xcode项目,在Storyboard中拖放一个适当大小的TextView控件,在右边栏的检查器四中设置好显示的文字内容和背景颜色。将TextView关联成TRViewControlle的属性textView。
然后在TRViewController类中的viewDidLoad方法中创建一个UIPinchGestureRecognizer手势pinchGR,使用initWithTarget: action:方法进行初始化并添加事件方法pinch:。将pinchGR添加到self.view中。
UIPinchGestureRecognizer类型的手势有两个常用的属性scale和velocity,scale表示缩放的比例,velocity表示缩放的速度。这两个属性都为只读属性。
最后实现pinch:方法,该方法中根据velocity属性的值判断是否显示textView,根据scale属性的值计算textView的字体大小。
3.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目搭建界面
首先创建Xcode项目,在Storyboard中拖放一个适当大小的TextView控件,在右边栏的检查器四中设置好显示的文字内容和背景颜色。将TextView关联成TRViewControlle的属性textView,代码如下所示:
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet UITextView *textView;
- @end
步骤二:创建pinch手势,添加到界面
在TRViewController类中的viewDidLoad方法中创建一个UIPinchGestureRecognizer手势pinchGR,使用initWithTarget: action:方法进行初始化并添加事件方法pinch:,并将pinchGR添加到self.view中,代码如下所示:
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
- [self.view addGestureRecognizer:pinchGR];
- }
步骤三:实现事件方法pinch:
实现pinch:方法,该方法中根据velocity属性的值判断是否显示textView,当velocity的值小于-10时则隐藏textView,大于10 则显示textView。再根据scale属性的值计算textView的字体大小,代码如下所示:
- - (void)pinch:(UIPinchGestureRecognizer *)gr
- {
- if (gr.velocity < -10) {
- self.textView.hidden = YES;
- }else if (gr.velocity > 10) {
- self.textView.hidden = NO;
- }else{
- self.textView.font = [UIFont systemFontOfSize:17 * gr.scale];
- }
- }
3.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet UITextView *textView;
- @end
- @implementation TRViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
- [self.view addGestureRecognizer:pinchGR];
- }
- - (void)pinch:(UIPinchGestureRecognizer *)gr
- {
- if (gr.velocity < -10) {
- self.textView.hidden = YES;
- }else if (gr.velocity > 10) {
- self.textView.hidden = NO;
- }else{
- self.textView.font = [UIFont systemFontOfSize:17 * gr.scale];
- }
- }
- @end
4 使用拖动手势移动图片
4.1 问题
UIPanGestureRecognizer拖动手势,通常用于移动某个视图的位置,本案例使用UIPanGestureRecognizer拖动手势移动图片,根据手指触屏的坐标改变图片的位置,如图-8、图-9所示:
图-8
图-9
4.2 方案
首先创建Xcode项目,在Storyboard中拖放一个适当大小的ImageView控件,在右边栏的检查器四中设置好显示图片。将ImageView控件关联成TRViewControlle的属性imageView。
然后在TRViewController类中的viewDidLoad方法中创建一个UIPanGestureRecognizer手势panGR,使用initWithTarget: action:方法进行初始化并添加事件方法pan:。将panGR添加到self.view中。
所有的手势都有一个UIGestureRecognizerState枚举类型的属性state,用来表示手势的状态,包括手势的开始、变化和结束。
最后实现pan:方法,该方法中根据手势不同的状态改变imageView的坐标和大小,使imageView的center根据手指触摸点改变。
4.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目搭建界面
首先创建Xcode项目,在Storyboard中拖放一个适当大小的Imageview控件,在右边栏的检查器四中设置好显示图片。将ImageView控件关联成TRViewControlle的属性imageView,代码如下所示:
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet UIImageView *imageView;
- @end
步骤二:创建pan手势,添加到界面
在TRViewController类中的viewDidLoad方法中创建一个UIPanGestureRecognizer手势panGR,使用initWithTarget: action:方法进行初始化并添加事件方法pan:,并将panGR添加到self.view中,代码如下所示:
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
- panGR.minimumNumberOfTouches = 1;
- [self.view addGestureRecognizer:panGR];
- }
步骤三:实现事件方法pan:
实现pan:方法,该方法中根据手势不同的状态改变imageView的坐标和大小,使imageView的center根据手指触摸点改变。
当state的值等于UIGestureRecognizerStateBegan时将imageView的大小设置为原来大小的0.5倍,当state的值等于UIGestureRecognizerStateChanged时imageView的center跟着手指触摸点移动,当state的值等于UIGestureRecognizerStateEnded时imageView的大小变回原来的大小,代码如下所示:
- - (void)pan:(UIPanGestureRecognizer *)gr
- {
- if (gr.state == UIGestureRecognizerStateBegan) {
- self.imageView.frame = CGRectMake(self.imageView.frame.origin.x, self.imageView.frame.origin.y, self.imageView.frame.size.width*0.5, self.imageView.frame.size.height*0.5);
- }else if(gr.state == UIGestureRecognizerStateChanged){
- self.imageView.center = [gr locationInView:self.view];
- }else if(gr.state == UIGestureRecognizerStateEnded){
- self.imageView.frame = CGRectMake(self.imageView.frame.origin.x, self.imageView.frame.origin.y, self.imageView.frame.size.width*2, self.imageView.frame.size.height*2);
- }
- }
4.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet UIImageView *imageView;
- @end
- @implementation TRViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
- panGR.minimumNumberOfTouches = 1;
- [self.view addGestureRecognizer:panGR];
- }
- - (void)pan:(UIPanGestureRecognizer *)gr
- {
- if (gr.state == UIGestureRecognizerStateBegan) {
- self.imageView.frame = CGRectMake(self.imageView.frame.origin.x, self.imageView.frame.origin.y, self.imageView.frame.size.width*0.5, self.imageView.frame.size.height*0.5);
- }else if(gr.state == UIGestureRecognizerStateChanged){
- self.imageView.center = [gr locationInView:self.view];
- }else if(gr.state == UIGestureRecognizerStateEnded){
- self.imageView.frame = CGRectMake(self.imageView.frame.origin.x, self.imageView.frame.origin.y, self.imageView.frame.size.width*2, self.imageView.frame.size.height*2);
- }
- }
- @end
5 结合手势对图片进行缩放、旋转和位移
5.1 问题
变形transform是视图(View)的一个CGAffineTransform结构体类型的属性,可以使视图产生缩放、旋转、位移等变化。本案例结合手势实现对一张图片的变形,包括缩放、旋转和位移,如图-10、图-11所示:
图-10
图-11
5.2 方案
首先创建Xcode项目,在TRViewController类中定义一个UIImageView类型的属性imageView。然后在viewDidLoad方法中创建一个UIImageView对象imageView添加到父视图中,并根据父视图的宽高比计算出imageView的宽高,将imageView放置在父视图的中间。将属性imageView指向该对象。
其次将imageView的用户交互功能打开,然后在viewDidLoad方法中创建一个旋转手势rotationGR,将手势的响应方法命名为rotate:,最后将旋转手势添加到imageView上。
rotate:方法中通过CGAffineTransformRotate函数改变imageView的transform属性,实现imageView旋转的功能。
然后在viewDidLoad方法中创建一个缩放手势pinchGR,将手势的响应方法命名为pinch:,最后将缩放手势添加到imageView上。
pinch:方法中通过CGAffineTransformScale函数改变imageView的transform属性,实现imageView缩放的功能。
默认情况下,视图在同一时刻只能识别一种手势。如果想要同时识别多种手势就需要给手势指定委托,让手势对象之间进行通信协商两个手势是否能够一起工作。
本案例中旋转手势和缩放手势是可以一起工作的,所以将rotationGR和pinchGR的delegate赋值为TRViewController,TRViewController通过实现协议方法shouldRecognizeSimultaneouslyWithGestureRecognizer:使两个手势能够同时被识别。
最后再创建一个拖拽手势和双击手势添加到imageView上,分别实现拖拽手势和双击手势的响应方法。
5.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建imageView对象
在TRViewController类中定义一个UIImageView类型的属性imageView。然后在viewDidLoad方法中创建一个UIImageView对象imageView添加到父视图中,并根据父视图的宽高比计算出imageView的宽高,将imageView放置在父视图的中间。将属性imageView指向该对象,代码如下所示:
- //根据父视图宽高计算imageView的宽高
- - (void)relocation
- {
- float horizontalScale = self.view.bounds.size.width / self.imageView.bounds.size.width;
- float verticalScale = self.view.bounds.size.height / self.imageView.bounds.size.height;
- float realScale = horizontalScale < verticalScale ? horizontalScale:verticalScale;
- self.imageView.transform = CGAffineTransformMakeScale(realScale, realScale);
- }
- //创建imageView对象
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"Elephant.jpg"]];
- self.imageView = imageView;
- [self.view addSubview:imageView];
- imageView.center = self.view.center;
- [self relocation];
- }
步骤二:创建旋转手势,添加到imageView
首先将imageView的用户交互功能打开,然后在viewDidLoad方法中创建一个旋转手势rotationGR,将手势的响应方法命名为rotate:,最后将旋转手势添加到imageView上,代码如下所示:
- //打开imageView的交互功能
- imageView.userInteractionEnabled = YES;
- //创建旋转手势
- UIRotationGestureRecognizer *rotationGR = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotate:)];
- [imageView addGestureRecognizer:rotationGR];
实现rotate:方法,在该方法中通过CGAffineTransformRotate函数改变imageView的transform属性,实现imageView旋转的功能,代码如下所示:
- - (void)rotate:(UIRotationGestureRecognizer *)gr
- {
- self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, gr.rotation);
- gr.rotation = 0;
- }
步骤三:创建缩放手势,添加到imageView
首先在viewDidLoad方法中创建一个缩放手势pinchGR,将手势的响应方法命名为pinch:,再将缩放手势添加到imageView上,代码如下所示:
- UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
- [imageView addGestureRecognizer:pinchGR];
然后实现pinch:方法,在该方法中通过CGAffineTransformScale函数改变imageView的transform属性,实现imageView缩放的功能,代码如下所示:
- - (void)pinch:(UIPinchGestureRecognizer *)gr
- {
- self.imageView.transform = CGAffineTransformScale(self.imageView.transform, gr.scale, gr.scale);
- gr.scale = 1;
- }
步骤四:使旋转和缩放手势能够同时被识别
首先在viewDidLoad方法中将rotationGR和pinchGR的delegate属性赋值为当前视图控制器即TRViewController,代码如下所示:
- //通过委托,让rotation和pinch可以同时被识别
- rotationGR.delegate = self;
- pinchGR.delegate = self;
然后在TRViewController类中通过实现协议方法shouldRecognizeSimultaneouslyWithGestureRecognizer:,使两个手势能够同时被识别,代码如下所示:
- //两个手势对象是否可以同时识别
- -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
- shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
- {
- if ([gestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class] ]&& [otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
- return YES;
- }else if([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]&&[otherGestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class]]){
- return YES;
- }
- return NO;
- }
步骤五:创建拖拽手势和双击手势
首先在viewDidLoad方法中创建一个拖拽手势panGR,将手势的响应方法命名为pan:,然后将缩放手势添加到imageView上,代码如下所示:
- UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
- [imageView addGestureRecognizer:panGR];
然后实现pan:方法,该方法中通过CGAffineTransformTranslate函数改变imageView的transform属性,实现imageView的位移功能,代码如下所示:
再创建一个双击手势tapGR,将手势的响应方法命名为tap:,然后将缩放手势添加到imageView上,代码如下所示:
- UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
- tapGR.numberOfTapsRequired = 2;
- [imageView addGestureRecognizer:tapGR];
最后实现tap:方法,双击imageView则将imageView置为最初的状态。所示tap:方法中直接调用relocation方法即可,代码如下所示:
- - (void)tap:(UITapGestureRecognizer *)gr
- {
- [self relocation];
- }
5.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @interface TRViewController () <UIGestureRecognizerDelegate>
- @property (strong, nonatomic) UIImageView *imageView;
- @end
- @implementation TRViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"Elephant.jpg"]];
- self.imageView = imageView;
- [self.view addSubview:imageView];
- imageView.center = self.view.center;
- [self relocation];
- //打开用户交互
- imageView.userInteractionEnabled = YES;
- //添加旋转手势
- UIRotationGestureRecognizer *rotationGR = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotate:)];
- [imageView addGestureRecognizer:rotationGR];
- //添加缩放手势
- UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
- [imageView addGestureRecognizer:pinchGR];
- //添加拖拽手势
- UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
- [imageView addGestureRecognizer:panGR];
- //添加双击手势
- UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
- tapGR.numberOfTapsRequired = 2;
- [imageView addGestureRecognizer:tapGR];
- //通过委托,让rotation和pinch可以同时被识别
- rotationGR.delegate = self;
- pinchGR.delegate = self;
- }
- - (void)rotate:(UIRotationGestureRecognizer *)gr
- {
- self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, gr.rotation);
- gr.rotation = 0;
- }
- - (void)pinch:(UIPinchGestureRecognizer *)gr
- {
- self.imageView.transform = CGAffineTransformScale(self.imageView.transform, gr.scale, gr.scale);
- gr.scale = 1;
- }
- - (void)pan:(UIPanGestureRecognizer *)gr
- {
- CGPoint p = [gr translationInView:self.imageView];
- self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, p.x, p.y);
- [gr setTranslation:CGPointZero inView:self.imageView];
- }
- - (void)tap:(UITapGestureRecognizer *)gr
- {
- [self relocation];
- }
- - (void)relocation
- {
- float horizontalScale = self.view.bounds.size.width / self.imageView.bounds.size.width;
- float verticalScale = self.view.bounds.size.height / self.imageView.bounds.size.height;
- float realScale = horizontalScale < verticalScale ? horizontalScale:verticalScale;
- self.imageView.transform = CGAffineTransformMakeScale(realScale, realScale);
- }
- #pragma mark - UIGestureRecognizerDelegate
- //两个手势对象是否可以同时识别
- - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
- {
- if ([gestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class] ]&& [otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
- return YES;
- }else if([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]&&[otherGestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class]]){
- return YES;
- }
- return NO;
- }
- @end
6 演示坐标系四个成员之间的关系
6.1 问题
本案例直接在上一个案例的基础之上增加两个Label查看frame、bounds以及transform之间的关系,如图-12所示:
图-12
6.2 方案
首先在上一个案例的界面上添加两个UILabel控件frameLabel和boundslabel,分别用于显示imageView的frame和bounds值。
然后为了观察frame、bounds根据变形产生的变化,在各个手势方法中添加一个用于实时显示imageView的frame和bounds的方法trace。运行程序,可以看出frame会随着transform的变化而变化,bounds始终保持不变。
最后在imageView的右上角75%的位置上添加一个UILable类型的子视图。
6.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:在界面上添加frameLabel和boundslabel
首先在上一个案例的界面上添加两个UILabel控件frameLabel和boundslabel,分别用于显示imageView的frame和bounds值,代码如下所示:
- UILabel *frameLabel = [[UILabel alloc]init];
- self.frameLabel = frameLabel;
- frameLabel.frame = CGRectMake(10, 30, 300, 30);
- frameLabel.font = [UIFont italicSystemFontOfSize:20];
- frameLabel.textColor = [UIColor redColor];
- frameLabel.backgroundColor = [UIColor clearColor];
- frameLabel.shadowColor = [UIColor greenColor];
- frameLabel.shadowOffset = CGSizeMake(1, 1);
- frameLabel.text = @"Frame";
- [self.view addSubview:frameLabel];
- UILabel *boundsLabel = [[UILabel alloc]init];
- self.boundsLabel = boundsLabel;
- boundsLabel.frame = CGRectMake(10, 70, 300, 30);
- boundsLabel.font = [UIFont italicSystemFontOfSize:20];
- boundsLabel.textColor = [UIColor redColor];
- boundsLabel.backgroundColor = [UIColor clearColor];
- boundsLabel.shadowColor = [UIColor greenColor];
- boundsLabel.shadowOffset = CGSizeMake(1, 1);
- boundsLabel.text = @"Bounds";
- [self.view addSubview:boundsLabel];
步骤二:实现trace方法
为了观察frame、bounds根据变形产生的变化,在各个手势方法中添加一个用于实时显示imageView的frame和bounds的方法trace,代码如下所示:
- - (void)trace
- {
- self.frameLabel.text = [NSString stringWithFormat:@"%.2f, %.2f, %.2f, %.2f", self.imageView.frame.origin.x, self.imageView.frame.origin.y, self.imageView.frame.size.width, self.imageView.frame.size.height];
- self.boundsLabel.text = [NSString stringWithFormat:@"%.2f, %.2f, %.2f, %.2f", self.imageView.bounds.origin.x, self.imageView.bounds.origin.y, self.imageView.bounds.size.width, self.imageView.bounds.size.height];
- }
然后运行程序,可以看出frame会随着transform的变化而变化,而bounds始终保持不变。
步骤三:在imageView的右上角子视图label
在imageView的右上角75%的位置上添加一个UILable类型的子视图label。此时label的frame需要根据imageView的bounds来进行计算,而不是imageView的frame,代码如下所示:
- UILabel *label = [[UILabel alloc]init];
- label.backgroundColor = [UIColor redColor];
- CGRect frame = CGRectMake(imageView.bounds.size.width * 0.75, imageView.bounds.size.height * 0.25, 200, 200);
- label.frame = frame;
- [imageView addSubview:label];
6.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @interface TRViewController () <UIGestureRecognizerDelegate>
- @property (strong, nonatomic) UIImageView *imageView;
- @property (strong, nonatomic) UILabel *frameLabel;
- @property (strong, nonatomic) UILabel *boundsLabel;
- @end
- @implementation TRViewController
- - (void)relocation
- {
- float horizontalScale = self.view.bounds.size.width / self.imageView.bounds.size.width;
- float verticalScale = self.view.bounds.size.height / self.imageView.bounds.size.height;
- float realScale = horizontalScale < verticalScale ? horizontalScale:verticalScale;
- self.imageView.transform = CGAffineTransformMakeScale(realScale, realScale);
- }
- - (void)trace
- {
- self.frameLabel.text = [NSString stringWithFormat:@"%.2f, %.2f, %.2f, %.2f", self.imageView.frame.origin.x, self.imageView.frame.origin.y, self.imageView.frame.size.width, self.imageView.frame.size.height];
- self.boundsLabel.text = [NSString stringWithFormat:@"%.2f, %.2f, %.2f, %.2f", self.imageView.bounds.origin.x, self.imageView.bounds.origin.y, self.imageView.bounds.size.width, self.imageView.bounds.size.height];
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- //屏幕上增加两行显示imageView的frame和bounds的Label
- UILabel *frameLabel = [[UILabel alloc]init];
- self.frameLabel = frameLabel;
- frameLabel.frame = CGRectMake(10, 30, 300, 30);
- frameLabel.font = [UIFont italicSystemFontOfSize:20];
- frameLabel.textColor = [UIColor redColor];
- frameLabel.backgroundColor = [UIColor clearColor];
- frameLabel.shadowColor = [UIColor greenColor];
- frameLabel.shadowOffset = CGSizeMake(1, 1);
- frameLabel.text = @"Frame";
- [self.view addSubview:frameLabel];
- UILabel *boundsLabel = [[UILabel alloc]init];
- self.boundsLabel = boundsLabel;
- boundsLabel.frame = CGRectMake(10, 70, 300, 30);
- boundsLabel.font = [UIFont italicSystemFontOfSize:20];
- boundsLabel.textColor = [UIColor redColor];
- boundsLabel.backgroundColor = [UIColor clearColor];
- boundsLabel.shadowColor = [UIColor greenColor];
- boundsLabel.shadowOffset = CGSizeMake(1, 1);
- boundsLabel.text = @"Bounds";
- [self.view addSubview:boundsLabel];
- UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"Elephant.jpg"]];
- self.imageView = imageView;
- [self.view insertSubview:imageView atIndex:0];
- imageView.center = self.view.center;
- [self relocation];
- [self trace];
- imageView.userInteractionEnabled = YES;//打开用户交互
- UIRotationGestureRecognizer *rotationGR = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotate:)];
- [imageView addGestureRecognizer:rotationGR];
- UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
- [imageView addGestureRecognizer:pinchGR];
- UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
- [imageView addGestureRecognizer:panGR];
- //7.
- UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
- tapGR.numberOfTapsRequired = 2;
- [imageView addGestureRecognizer:tapGR];
- //8. 让rotation和pinch可以同时被识别
- rotationGR.delegate = self;
- pinchGR.delegate = self;
- //将一个子视图加入到imageView中的右上角75%的位置
- UILabel *label = [[UILabel alloc]init];
- label.backgroundColor = [UIColor redColor];
- CGRect frame = CGRectMake(imageView.bounds.size.width * 0.75, imageView.bounds.size.height * 0.25, 200, 200);
- label.frame = frame;
- [imageView addSubview:label];
- }
- - (void)rotate:(UIRotationGestureRecognizer *)gr
- {
- self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, gr.rotation);
- gr.rotation = 0;
- [self trace];
- }
- - (void)pinch:(UIPinchGestureRecognizer *)gr
- {
- self.imageView.transform = CGAffineTransformScale(self.imageView.transform, gr.scale, gr.scale);
- gr.scale = 1;
- [self trace];
- }
- - (void)pan:(UIPanGestureRecognizer *)gr
- {
- CGPoint p = [gr translationInView:self.imageView];
- self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, p.x, p.y);
- [gr setTranslation:CGPointZero inView:self.imageView];
- [self trace];
- }
- - (void)tap:(UITapGestureRecognizer *)gr
- {
- [self relocation];
- }
- #pragma mark - UIGestureRecognizerDelegate
- //两个手势对象是否可以同时识别
- - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
- {
- if ([gestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class] ]&& [otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
- return YES;
- }else if([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]&&[otherGestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class]]){
- return YES;
- }
- return NO;
- }
- @end