• 手势与变形 、 视图与坐标系


    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,代码如下所示:

     
    1. @interface TRViewController ()
    2. @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    3. @property (weak, nonatomic) IBOutlet UILabel *label;
    4. @end

    然后在TRViewController类中的viewDidLoad方法中创建一个UITapGestureRecognizer手势tapGR,使用initWithTarget: action:方法进行初始化并添加事件方法tap:,代码如下所示:

     
    1. UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];

    将tap手势的numberOfTapsRequired属性设置为1,表示点击一下的意思即单击。最后将手势添加到view中,代码如下所示:

     
    1. - (void)viewDidLoad
    2. {
    3. [super viewDidLoad];
    4.     //创建手势对象
    5. UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
    6. //设置相关属性
    7. tapGR.numberOfTapsRequired = 1;
    8. tapGR.numberOfTouchesRequired = 1;
    9. //将手势对象加入到需要识别手势的视图
    10. [self.view addGestureRecognizer:tapGR];
    11. }

    最后实现方法tap:,当点击view则在label上显示“view被点击了一下”,代码如下所示:

    1. - (void)tap:(UITapGestureRecognizer *)gr
    2. {
    3. self.label.text = @"view被点击了一下";
    4. }

    步骤三:创建双击手势,添加到界面

    然后在TRViewController类中的viewDidLoad方法中创建一个UITapGestureRecognizer手势doubleTap,使用initWithTarget: action:方法进行初始化并添加事件方法doubleTap:,代码如下所示:

     
    1. UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(doubleTap:)];

    将doubleTap手势的numberOfTapsRequired属性设置为2,表示点击两下的意思即双击。最后将手势添加到view中,代码如下所示:

     
    1. - (void)viewDidLoad
    2. {
    3. [super viewDidLoad];
    4. UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
    5. tapGR.numberOfTapsRequired = 1;
    6. tapGR.numberOfTouchesRequired = 1;
    7. [self.view addGestureRecognizer:tapGR];
    8. UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(doubleTap:)];
    9. [doubleTap setNumberOfTapsRequired:2];
    10. [self.imageView addGestureRecognizer:doubleTap];
    11. }

    最后实现方法doubleap:,当点击imageView则在label上显示“imageView被点击了两下”,代码如下所示:

    1. -(void)doubleTap:(UITapGestureRecognizer*)gr {
    2. self.label.text = @"imageView被点击了两下";
    3. }

    1.4 完整代码

    本案例中,TRViewController.m文件中的完整代码如下所示:

     
    1. #import "TRViewController.h"
    2. @interface TRViewController ()
    3. @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    4. @property (weak, nonatomic) IBOutlet UILabel *label;
    5. @end
    6. @implementation TRViewController
    7. - (void)viewDidLoad
    8. {
    9. [super viewDidLoad];
    10.     //1. 创建手势对象
    11. UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
    12. //2. 设置相关属性
    13. tapGR.numberOfTapsRequired = 1;
    14. tapGR.numberOfTouchesRequired = 1;
    15. //3. 将手势对象加入到需要识别手势的视图
    16. [self.view addGestureRecognizer:tapGR];
    17. UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(doubleTap:)];
    18. [doubleTap setNumberOfTapsRequired:2];
    19. [self.imageView addGestureRecognizer:doubleTap];
    20. }
    21. - (void)tap:(UITapGestureRecognizer *)gr
    22. {
    23. self.label.text = @"view被点击了一下";
    24. }
    25. -(void)doubleTap:(UITapGestureRecognizer*)gr {
    26. self.label.text = @"imageView被点击了两下";
    27. }
    28. @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:,代码如下所示:

    1. UISwipeGestureRecognizer *swipeGR = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipe:)];

    将swipe手势的direction属性设置为左右,表示从右向左轻滑或者由左向右轻滑都可以触发手势的动作事件,并将手势添加到self.view中,代码如下所示:

     
    1. - (void)viewDidLoad
    2. {
    3. [super viewDidLoad];
    4.     UISwipeGestureRecognizer *swipeGR = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipe:)];
    5. swipeGR.direction = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight ;
    6. [self.view addGestureRecognizer:swipeGR];
    7. }

    步骤三:实现事件方法swipe:

    实现方法swipe:,当滑动图片则切换两个ImageView的显示顺序,代码如下所示:

    1. - (void)swipe:(UISwipeGestureRecognizer *)gr
    2. {
    3. [self.view exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
    4. NSLog(@"%@",self.view.subviews);
    5. }

    2.4 完整代码

    本案例中,TRViewController.m文件中的完整代码如下所示:

     
    1. #import "TRViewController.h"
    2. @implementation TRViewController
    3. - (void)viewDidLoad
    4. {
    5. [super viewDidLoad];
    6.     UISwipeGestureRecognizer *swipeGR = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipe:)];
    7. swipeGR.direction = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight ;
    8. [self.view addGestureRecognizer:swipeGR];
    9. }
    10. - (void)swipe:(UISwipeGestureRecognizer *)gr
    11. {
    12. [self.view exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
    13. NSLog(@"%@",self.view.subviews);
    14. }
    15. @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,代码如下所示:

     
    1. @interface TRViewController ()
    2. @property (weak, nonatomic) IBOutlet UITextView *textView;
    3. @end

    步骤二:创建pinch手势,添加到界面

    在TRViewController类中的viewDidLoad方法中创建一个UIPinchGestureRecognizer手势pinchGR,使用initWithTarget: action:方法进行初始化并添加事件方法pinch:,并将pinchGR添加到self.view中,代码如下所示:

     
    1. - (void)viewDidLoad
    2. {
    3. [super viewDidLoad];
    4.     UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
    5. [self.view addGestureRecognizer:pinchGR];
    6. }

    步骤三:实现事件方法pinch:

    实现pinch:方法,该方法中根据velocity属性的值判断是否显示textView,当velocity的值小于-10时则隐藏textView,大于10 则显示textView。再根据scale属性的值计算textView的字体大小,代码如下所示:

     
    1. - (void)pinch:(UIPinchGestureRecognizer *)gr
    2. {
    3. if (gr.velocity < -10) {
    4. self.textView.hidden = YES;
    5. }else if (gr.velocity > 10) {
    6. self.textView.hidden = NO;
    7. }else{
    8. self.textView.font = [UIFont systemFontOfSize:17 * gr.scale];
    9. }
    10. }

    3.4 完整代码

    本案例中,TRViewController.m文件中的完整代码如下所示:

     
    1. #import "TRViewController.h"
    2. @interface TRViewController ()
    3. @property (weak, nonatomic) IBOutlet UITextView *textView;
    4. @end
    5. @implementation TRViewController
    6. - (void)viewDidLoad
    7. {
    8. [super viewDidLoad];
    9.     UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
    10. [self.view addGestureRecognizer:pinchGR];
    11. }
    12. - (void)pinch:(UIPinchGestureRecognizer *)gr
    13. {
    14. if (gr.velocity < -10) {
    15. self.textView.hidden = YES;
    16. }else if (gr.velocity > 10) {
    17. self.textView.hidden = NO;
    18. }else{
    19. self.textView.font = [UIFont systemFontOfSize:17 * gr.scale];
    20. }
    21. }
    22. @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,代码如下所示:

    1. @interface TRViewController ()
    2. @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    3. @end

    步骤二:创建pan手势,添加到界面

    在TRViewController类中的viewDidLoad方法中创建一个UIPanGestureRecognizer手势panGR,使用initWithTarget: action:方法进行初始化并添加事件方法pan:,并将panGR添加到self.view中,代码如下所示:

     
    1. - (void)viewDidLoad
    2. {
    3. [super viewDidLoad];
    4.     UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
    5. panGR.minimumNumberOfTouches = 1;
    6. [self.view addGestureRecognizer:panGR];
    7. }

    步骤三:实现事件方法pan:

    实现pan:方法,该方法中根据手势不同的状态改变imageView的坐标和大小,使imageView的center根据手指触摸点改变。

    当state的值等于UIGestureRecognizerStateBegan时将imageView的大小设置为原来大小的0.5倍,当state的值等于UIGestureRecognizerStateChanged时imageView的center跟着手指触摸点移动,当state的值等于UIGestureRecognizerStateEnded时imageView的大小变回原来的大小,代码如下所示:

     
    1. - (void)pan:(UIPanGestureRecognizer *)gr
    2. {
    3. if (gr.state == UIGestureRecognizerStateBegan) {
    4. 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);
    5. }else if(gr.state == UIGestureRecognizerStateChanged){
    6. self.imageView.center = [gr locationInView:self.view];
    7. }else if(gr.state == UIGestureRecognizerStateEnded){
    8. 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);
    9. }
    10. }

    4.4 完整代码

    本案例中,TRViewController.m文件中的完整代码如下所示:

     
    1. #import "TRViewController.h"
    2. @interface TRViewController ()
    3. @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    4. @end
    5. @implementation TRViewController
    6. - (void)viewDidLoad
    7. {
    8. [super viewDidLoad];
    9.     UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
    10. panGR.minimumNumberOfTouches = 1;
    11. [self.view addGestureRecognizer:panGR];
    12. }
    13. - (void)pan:(UIPanGestureRecognizer *)gr
    14. {
    15. if (gr.state == UIGestureRecognizerStateBegan) {
    16. 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);
    17. }else if(gr.state == UIGestureRecognizerStateChanged){
    18. self.imageView.center = [gr locationInView:self.view];
    19. }else if(gr.state == UIGestureRecognizerStateEnded){
    20. 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);
    21. }
    22. }
    23. @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指向该对象,代码如下所示:

     
    1. //根据父视图宽高计算imageView的宽高
    2. - (void)relocation
    3. {
    4. float horizontalScale = self.view.bounds.size.width / self.imageView.bounds.size.width;
    5. float verticalScale = self.view.bounds.size.height / self.imageView.bounds.size.height;
    6. float realScale = horizontalScale < verticalScale ? horizontalScale:verticalScale;
    7. self.imageView.transform = CGAffineTransformMakeScale(realScale, realScale);
    8. }
    9. //创建imageView对象
    10. - (void)viewDidLoad
    11. {
    12. [super viewDidLoad];
    13.     UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"Elephant.jpg"]];
    14. self.imageView = imageView;
    15. [self.view addSubview:imageView];
    16. imageView.center = self.view.center;
    17. [self relocation];
    18. }

    步骤二:创建旋转手势,添加到imageView

    首先将imageView的用户交互功能打开,然后在viewDidLoad方法中创建一个旋转手势rotationGR,将手势的响应方法命名为rotate:,最后将旋转手势添加到imageView上,代码如下所示:

    1. //打开imageView的交互功能
    2. imageView.userInteractionEnabled = YES;
    3. //创建旋转手势
    4. UIRotationGestureRecognizer *rotationGR = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotate:)];
    5. [imageView addGestureRecognizer:rotationGR];

    实现rotate:方法,在该方法中通过CGAffineTransformRotate函数改变imageView的transform属性,实现imageView旋转的功能,代码如下所示:

    1. - (void)rotate:(UIRotationGestureRecognizer *)gr
    2. {
    3. self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, gr.rotation);
    4. gr.rotation = 0;
    5. }

    步骤三:创建缩放手势,添加到imageView

    首先在viewDidLoad方法中创建一个缩放手势pinchGR,将手势的响应方法命名为pinch:,再将缩放手势添加到imageView上,代码如下所示:

     
    1. UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
    2. [imageView addGestureRecognizer:pinchGR];

    然后实现pinch:方法,在该方法中通过CGAffineTransformScale函数改变imageView的transform属性,实现imageView缩放的功能,代码如下所示:

    1. - (void)pinch:(UIPinchGestureRecognizer *)gr
    2. {
    3. self.imageView.transform = CGAffineTransformScale(self.imageView.transform, gr.scale, gr.scale);
    4. gr.scale = 1;
    5. }

    步骤四:使旋转和缩放手势能够同时被识别

    首先在viewDidLoad方法中将rotationGR和pinchGR的delegate属性赋值为当前视图控制器即TRViewController,代码如下所示:

     
    1. //通过委托,让rotation和pinch可以同时被识别
    2. rotationGR.delegate = self;
    3. pinchGR.delegate = self;

    然后在TRViewController类中通过实现协议方法shouldRecognizeSimultaneouslyWithGestureRecognizer:,使两个手势能够同时被识别,代码如下所示:

     
    1. //两个手势对象是否可以同时识别
    2. -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
    3. shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    4. {
    5. if ([gestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class] ]&& [otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
    6. return YES;
    7. }else if([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]&&[otherGestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class]]){
    8. return YES;
    9. }
    10. return NO;
    11. }

    步骤五:创建拖拽手势和双击手势

    首先在viewDidLoad方法中创建一个拖拽手势panGR,将手势的响应方法命名为pan:,然后将缩放手势添加到imageView上,代码如下所示:

     
    1. UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
    2. [imageView addGestureRecognizer:panGR];

    然后实现pan:方法,该方法中通过CGAffineTransformTranslate函数改变imageView的transform属性,实现imageView的位移功能,代码如下所示:

    再创建一个双击手势tapGR,将手势的响应方法命名为tap:,然后将缩放手势添加到imageView上,代码如下所示:

    1. UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
    2. tapGR.numberOfTapsRequired = 2;
    3. [imageView addGestureRecognizer:tapGR];

    最后实现tap:方法,双击imageView则将imageView置为最初的状态。所示tap:方法中直接调用relocation方法即可,代码如下所示:

     
    1. - (void)tap:(UITapGestureRecognizer *)gr
    2. {
    3. [self relocation];
    4. }

    5.4 完整代码

    本案例中,TRViewController.m文件中的完整代码如下所示:

     
    1. #import "TRViewController.h"
    2. @interface TRViewController () <UIGestureRecognizerDelegate>
    3. @property (strong, nonatomic) UIImageView *imageView;
    4. @end
    5. @implementation TRViewController
    6. - (void)viewDidLoad
    7. {
    8. [super viewDidLoad];
    9.     UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"Elephant.jpg"]];
    10. self.imageView = imageView;
    11. [self.view addSubview:imageView];
    12. imageView.center = self.view.center;
    13. [self relocation];
    14. //打开用户交互
    15. imageView.userInteractionEnabled = YES;
    16. //添加旋转手势
    17. UIRotationGestureRecognizer *rotationGR = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotate:)];
    18. [imageView addGestureRecognizer:rotationGR];
    19. //添加缩放手势
    20. UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
    21. [imageView addGestureRecognizer:pinchGR];
    22. //添加拖拽手势
    23. UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
    24. [imageView addGestureRecognizer:panGR];
    25. //添加双击手势
    26. UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
    27. tapGR.numberOfTapsRequired = 2;
    28. [imageView addGestureRecognizer:tapGR];
    29. //通过委托,让rotation和pinch可以同时被识别
    30. rotationGR.delegate = self;
    31. pinchGR.delegate = self;
    32. }
    33. - (void)rotate:(UIRotationGestureRecognizer *)gr
    34. {
    35. self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, gr.rotation);
    36. gr.rotation = 0;
    37. }
    38. - (void)pinch:(UIPinchGestureRecognizer *)gr
    39. {
    40. self.imageView.transform = CGAffineTransformScale(self.imageView.transform, gr.scale, gr.scale);
    41. gr.scale = 1;
    42. }
    43. - (void)pan:(UIPanGestureRecognizer *)gr
    44. {
    45. CGPoint p = [gr translationInView:self.imageView];
    46. self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, p.x, p.y);
    47. [gr setTranslation:CGPointZero inView:self.imageView];
    48. }
    49. - (void)tap:(UITapGestureRecognizer *)gr
    50. {
    51. [self relocation];
    52. }
    53. - (void)relocation
    54. {
    55. float horizontalScale = self.view.bounds.size.width / self.imageView.bounds.size.width;
    56. float verticalScale = self.view.bounds.size.height / self.imageView.bounds.size.height;
    57. float realScale = horizontalScale < verticalScale ? horizontalScale:verticalScale;
    58. self.imageView.transform = CGAffineTransformMakeScale(realScale, realScale);
    59. }
    60. #pragma mark - UIGestureRecognizerDelegate
    61. //两个手势对象是否可以同时识别
    62. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    63. {
    64. if ([gestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class] ]&& [otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
    65. return YES;
    66. }else if([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]&&[otherGestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class]]){
    67. return YES;
    68. }
    69. return NO;
    70. }
    71. @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值,代码如下所示:

     
    1. UILabel *frameLabel = [[UILabel alloc]init];
    2. self.frameLabel = frameLabel;
    3. frameLabel.frame = CGRectMake(10, 30, 300, 30);
    4. frameLabel.font = [UIFont italicSystemFontOfSize:20];
    5. frameLabel.textColor = [UIColor redColor];
    6. frameLabel.backgroundColor = [UIColor clearColor];
    7. frameLabel.shadowColor = [UIColor greenColor];
    8. frameLabel.shadowOffset = CGSizeMake(1, 1);
    9. frameLabel.text = @"Frame";
    10. [self.view addSubview:frameLabel];
    11. UILabel *boundsLabel = [[UILabel alloc]init];
    12. self.boundsLabel = boundsLabel;
    13. boundsLabel.frame = CGRectMake(10, 70, 300, 30);
    14. boundsLabel.font = [UIFont italicSystemFontOfSize:20];
    15. boundsLabel.textColor = [UIColor redColor];
    16. boundsLabel.backgroundColor = [UIColor clearColor];
    17. boundsLabel.shadowColor = [UIColor greenColor];
    18. boundsLabel.shadowOffset = CGSizeMake(1, 1);
    19. boundsLabel.text = @"Bounds";
    20. [self.view addSubview:boundsLabel];

    步骤二:实现trace方法

    为了观察frame、bounds根据变形产生的变化,在各个手势方法中添加一个用于实时显示imageView的frame和bounds的方法trace,代码如下所示:

     
    1. - (void)trace
    2. {
    3. 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];
    4. 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];
    5. }

    然后运行程序,可以看出frame会随着transform的变化而变化,而bounds始终保持不变。

    步骤三:在imageView的右上角子视图label

    在imageView的右上角75%的位置上添加一个UILable类型的子视图label。此时label的frame需要根据imageView的bounds来进行计算,而不是imageView的frame,代码如下所示:

     
    1. UILabel *label = [[UILabel alloc]init];
    2. label.backgroundColor = [UIColor redColor];
    3. CGRect frame = CGRectMake(imageView.bounds.size.width * 0.75, imageView.bounds.size.height * 0.25, 200, 200);
    4. label.frame = frame;
    5. [imageView addSubview:label];

    6.4 完整代码

    本案例中,TRViewController.m文件中的完整代码如下所示:

     
    1. #import "TRViewController.h"
    2. @interface TRViewController () <UIGestureRecognizerDelegate>
    3. @property (strong, nonatomic) UIImageView *imageView;
    4. @property (strong, nonatomic) UILabel *frameLabel;
    5. @property (strong, nonatomic) UILabel *boundsLabel;
    6. @end
    7. @implementation TRViewController
    8. - (void)relocation
    9. {
    10. float horizontalScale = self.view.bounds.size.width / self.imageView.bounds.size.width;
    11. float verticalScale = self.view.bounds.size.height / self.imageView.bounds.size.height;
    12. float realScale = horizontalScale < verticalScale ? horizontalScale:verticalScale;
    13. self.imageView.transform = CGAffineTransformMakeScale(realScale, realScale);
    14. }
    15. - (void)trace
    16. {
    17. 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];
    18. 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];
    19. }
    20. - (void)viewDidLoad
    21. {
    22. [super viewDidLoad];
    23. //屏幕上增加两行显示imageView的frame和bounds的Label
    24. UILabel *frameLabel = [[UILabel alloc]init];
    25. self.frameLabel = frameLabel;
    26. frameLabel.frame = CGRectMake(10, 30, 300, 30);
    27. frameLabel.font = [UIFont italicSystemFontOfSize:20];
    28. frameLabel.textColor = [UIColor redColor];
    29. frameLabel.backgroundColor = [UIColor clearColor];
    30. frameLabel.shadowColor = [UIColor greenColor];
    31. frameLabel.shadowOffset = CGSizeMake(1, 1);
    32. frameLabel.text = @"Frame";
    33. [self.view addSubview:frameLabel];
    34. UILabel *boundsLabel = [[UILabel alloc]init];
    35. self.boundsLabel = boundsLabel;
    36. boundsLabel.frame = CGRectMake(10, 70, 300, 30);
    37. boundsLabel.font = [UIFont italicSystemFontOfSize:20];
    38. boundsLabel.textColor = [UIColor redColor];
    39. boundsLabel.backgroundColor = [UIColor clearColor];
    40. boundsLabel.shadowColor = [UIColor greenColor];
    41. boundsLabel.shadowOffset = CGSizeMake(1, 1);
    42. boundsLabel.text = @"Bounds";
    43. [self.view addSubview:boundsLabel];
    44.     UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"Elephant.jpg"]];
    45. self.imageView = imageView;
    46. [self.view insertSubview:imageView atIndex:0];
    47. imageView.center = self.view.center;
    48. [self relocation];
    49. [self trace];
    50. imageView.userInteractionEnabled = YES;//打开用户交互
    51. UIRotationGestureRecognizer *rotationGR = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotate:)];
    52. [imageView addGestureRecognizer:rotationGR];
    53. UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
    54. [imageView addGestureRecognizer:pinchGR];
    55. UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
    56. [imageView addGestureRecognizer:panGR];
    57. //7.
    58. UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
    59. tapGR.numberOfTapsRequired = 2;
    60. [imageView addGestureRecognizer:tapGR];
    61. //8. 让rotation和pinch可以同时被识别
    62. rotationGR.delegate = self;
    63. pinchGR.delegate = self;
    64. //将一个子视图加入到imageView中的右上角75%的位置
    65. UILabel *label = [[UILabel alloc]init];
    66. label.backgroundColor = [UIColor redColor];
    67. CGRect frame = CGRectMake(imageView.bounds.size.width * 0.75, imageView.bounds.size.height * 0.25, 200, 200);
    68. label.frame = frame;
    69. [imageView addSubview:label];
    70. }
    71. - (void)rotate:(UIRotationGestureRecognizer *)gr
    72. {
    73. self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, gr.rotation);
    74. gr.rotation = 0;
    75. [self trace];
    76. }
    77. - (void)pinch:(UIPinchGestureRecognizer *)gr
    78. {
    79. self.imageView.transform = CGAffineTransformScale(self.imageView.transform, gr.scale, gr.scale);
    80. gr.scale = 1;
    81. [self trace];
    82. }
    83. - (void)pan:(UIPanGestureRecognizer *)gr
    84. {
    85. CGPoint p = [gr translationInView:self.imageView];
    86. self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, p.x, p.y);
    87. [gr setTranslation:CGPointZero inView:self.imageView];
    88. [self trace];
    89. }
    90. - (void)tap:(UITapGestureRecognizer *)gr
    91. {
    92. [self relocation];
    93. }
    94. #pragma mark - UIGestureRecognizerDelegate
    95. //两个手势对象是否可以同时识别
    96. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    97. {
    98. if ([gestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class] ]&& [otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
    99. return YES;
    100. }else if([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]&&[otherGestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class]]){
    101. return YES;
    102. }
    103. return NO;
    104. }
    105. @end
     
  • 相关阅读:
    [C++]多源最短路径(带权有向图):【Floyd算法(动态规划法)】 VS n*Dijkstra算法(贪心算法)
    [C++]Yellow Cards
    [C++]哈夫曼树(最优满二叉树) / 哈夫曼编码(贪心算法)
    考研部分复习策略记录
    [C++/JavaScript]数据结构:栈和数列>案例引入(数制的转换)
    [C++]数据结构:线性表之(单)链表
    [C++]数据结构:线性表之顺序表
    自然语言处理(NLP)之个人小结
    NLP之TF-IDF与BM25原理探究
    [Python]Excel编程示例教程(openpyxl)
  • 原文地址:https://www.cnblogs.com/52190112cn/p/5049437.html
Copyright © 2020-2023  润新知