1. 程式人生 > >iOS手勢識別的詳細使用(拖動,縮放,旋轉,點選,手勢依賴,自定義手勢)

iOS手勢識別的詳細使用(拖動,縮放,旋轉,點選,手勢依賴,自定義手勢)

1、UIGestureRecognizer介紹

手勢識別在iOS上非常重要,手勢操作移動裝置的重要特徵,極大的增加了移動裝置使用便捷性。
iOS系統在3.2以後,為方便開發這使用一些常用的手勢,提供了UIGestureRecognizer類。手勢識別UIGestureRecognizer類是個抽象類,下面的子類是具體的手勢,開發這可以直接使用這些手勢識別。
  • Tap(點一下)
  • Pinch(二指往內或往外撥動,平時經常用到的縮放)
  • Rotation(旋轉)
  • Swipe(滑動,快速移動)
  • Pan (拖移,慢速移動)
  •  LongPress(長按)
UIGestureRecognizer的繼承關係如下:

2、使用手勢的步驟

使用手勢很簡單,分為兩步:
  1. 建立手勢例項。當建立手勢時,指定一個回撥方法,當手勢開始,改變、或結束時,回撥方法被呼叫。
  2. 新增到需要識別的View中。每個手勢只對應一個View,當螢幕觸控在View的邊界內時,如果手勢和預定的一樣,那就會回撥方法。
ps:一個手勢只能對應一個View,但是一個View可以有多個手勢。建議在真機上執行這些手勢,模擬器操作不太方便,可能導致你認為手勢失效。

3、Pan 拖動手勢:

  1. UIImageView *snakeImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"snake.png"]];  
  2. snakeImageView.frame = CGRectMake(50, 50, 100, 160);  
  3. UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc]  
  4.                                                 initWithTarget:self  
  5.                                                 action:@selector(handlePan:)];      
  6. [snakeImageView addGestureRecognizer:panGestureRecognizer];  
  7. [self.view setBackgroundColor:[UIColor whiteColor]];  
  8. [self.view addSubview:snakeImageView];  
新建一個ImageView,然後新增手勢回撥方法:
  1. - (void) handlePan:(UIPanGestureRecognizer*) recognizer  
  2. {  
  3.     CGPoint translation = [recognizer translationInView:self.view];  
  4.     recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,  
  5.                                    recognizer.view.center.y + translation.y);  
  6.     [recognizer setTranslation:CGPointZero inView:self.view];  
  7. }  

4、Pinch縮放手勢

  1. UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc]  
  2.                                                         initWithTarget:self  
  3.                                                         action:@selector(handlePinch:)];<p class="p1">[<span class="s1">snakeImageView</span> <span class="s2">addGestureRecognizer</span>:pinchGestureRecognizer];</p>  

  1. - (void) handlePinch:(UIPinchGestureRecognizer*) recognizer  
  2. {  
  3.     recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);  
  4.     recognizer.scale = 1;  
  5. }  

5、Rotation旋轉手勢

  1. UIRotationGestureRecognizer *rotateRecognizer = [[UIRotationGestureRecognizer alloc]  
  2.                                                  initWithTarget:self  
  3.                                                  action:@selector(handleRotate:)];  
  4. [snakeImageView addGestureRecognizer:rotateRecognizer];  
  1. - (void) handleRotate:(UIRotationGestureRecognizer*) recognizer  
  2. {  
  3.     recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation);  
  4.     recognizer.rotation = 0;  
  5. }  

 添加了這幾個手勢後,執行看效果,程式中的imageView放了一個                    /^\/^\                  _|__|  O|         \/     /~     \_/ \          \____|__________/  \                 \_______      \                         `\     \                 \                           |     |                  \                          /      /                    \                         /     /                       \\                       /      /                         \ \                      /     /                            \  \                    /     /             _----_            \   \                   /     /           _-~      ~-_         |   |                  (      (        _-~    _--_    ~-_     _/   |                   \      ~-____-~    _-~    ~-_    ~-_-~    /                     ~-_           _-~          ~-_       _-~                          ~--______-~                ~-___-~的圖片,在模擬器上拖動是沒問題的。縮放和旋轉有點問題,估計是因為在模擬器上的模擬的兩個接觸點距離在imageView的邊界外了,所以操作無效果。建議在真機上執行這個手勢。在模擬器上縮放和選擇的操作技巧:可以把imageView的frame值設定大一點,按住alt鍵,按下觸控板(不按下不行),這樣就可以旋轉和縮放了。

6、新增第二個ImagView並新增手勢

記住:一個手勢只能新增到一個View,兩個View當然要有兩個手勢的例項了
  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.     UIImageView *snakeImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"snake.png"]];  
  5.     UIImageView *dragonImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"dragon.png"]];  
  6.     snakeImageView.frame = CGRectMake(120, 120, 100, 160);  
  7.     dragonImageView.frame = CGRectMake(50, 50, 100, 160);  
  8.     [self.view addSubview:snakeImageView];  
  9.     [self.view addSubview:dragonImageView];  
  10.     for (UIView *view in self.view.subviews) {  
  11.         UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc]  
  12.                                                         initWithTarget:self  
  13.                                                         action:@selector(handlePan:)];  
  14.         UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc]  
  15.                                                             initWithTarget:self  
  16.                                                             action:@selector(handlePinch:)];  
  17.         UIRotationGestureRecognizer *rotateRecognizer = [[UIRotationGestureRecognizer alloc]  
  18.                                                          initWithTarget:self  
  19.                                                          action:@selector(handleRotate:)];  
  20.         [view addGestureRecognizer:panGestureRecognizer];  
  21.         [view addGestureRecognizer:pinchGestureRecognizer];  
  22.         [view addGestureRecognizer:rotateRecognizer];  
  23.         [view setUserInteractionEnabled:YES];  
  24.     }  
  25.     [self.view setBackgroundColor:[UIColor whiteColor]];       
  26. }  

多添加了一條龍的view,兩個view都能接收上面的三種手勢。執行效果如下:

7、拖動(pan手勢)速度(以較快的速度拖放後view有滑行的效果)

如何實現呢?
  1. 監視手勢是否結束
  2. 監視觸控的速度
  1. - (void) handlePan:(UIPanGestureRecognizer*) recognizer  
  2. {  
  3.     CGPoint translation = [recognizer translationInView:self.view];  
  4.     recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,  
  5.                                        recognizer.view.center.y + translation.y);  
  6.     [recognizer setTranslation:CGPointZero inView:self.view];  
  7.     if (recognizer.state == UIGestureRecognizerStateEnded) {  
  8.         CGPoint velocity = [recognizer velocityInView:self.view];  
  9.         CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));  
  10.         CGFloat slideMult = magnitude / 200;  
  11.         NSLog(@"magnitude: %f, slideMult: %f", magnitude, slideMult);  
  12.         float slideFactor = 0.1 * slideMult; // Increase for more of a slide
  13.         CGPoint finalPoint = CGPointMake(recognizer.view.center.x + (velocity.x * slideFactor),  
  14.                                          recognizer.view.center.y + (velocity.y * slideFactor));  
  15.         finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width);  
  16.         finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height);  
  17.         [UIView animateWithDuration:slideFactor*2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{  
  18.             recognizer.view.center = finalPoint;  
  19.         } completion:nil];  
  20.     }  
程式碼實現解析:
  1. 計算速度向量的長度(估計大部分都忘了)這些知識了。
  2. 如果速度向量小於200,那就會得到一個小於的小數,那麼滑行會很短
  3. 基於速度和速度因素計算一個終點
  4. 確保終點不會跑出父View的邊界
  5. 使用UIView動畫使view滑動到終點
執行後,快速拖動影象view放開會看到view還會在原來的方向滑行一段路。

8、同時觸發兩個view的手勢

手勢之間是互斥的,如果你想同時觸發蛇和龍的view,那麼需要實現協議

UIGestureRecognizerDelegate,

  1. @interface ViewController : UIViewController<UIGestureRecognizerDelegate>  
  2. @end  
並在協議這個方法裡返回YES。
  1. -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer  
  2. {  
  3.     return YES;  
  4. }  
把self作為代理設定給手勢:
  1. panGestureRecognizer.delegate = self;  
  2. pinchGestureRecognizer.delegate = self;  
  3. rotateRecognizer.delegate = self;  
這樣可以同時拖動或旋轉縮放兩個view了。

9、tap點選手勢

這裡為了方便看到tap的效果,當點選一下螢幕時,播放一個聲音。

為了播放聲音,我們加入AVFoundation.framework這個框架。

  1. - (AVAudioPlayer *)loadWav:(NSString *)filename {  
  2.     NSURL * url = [[NSBundle mainBundle] URLForResource:filename withExtension:@"wav"];  
  3.     NSError * error;  
  4.     AVAudioPlayer * player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];  
  5.     if (!player) {  
  6.         NSLog(@"Error loading %@: %@", url, error.localizedDescription);  
  7.     } else {  
  8.         [player prepareToPlay];  
  9.     }  
  10.     return player;  
  11. }  
我會在最後例子程式碼給出完整程式碼,新增手勢的步驟和前面一樣的。
  1. #import <UIKit/UIKit.h>
  2. #import <AVFoundation/AVFoundation.h>
  3. @interface ViewController : UIViewController<UIGestureRecognizerDelegate>  
  4. @property (strong) AVAudioPlayer * chompPlayer;  
  5. @property (strong) AVAudioPlayer * hehePlayer;  
  6. @end  
  1. - (void)handleTap:(UITapGestureRecognizer *)recognizer {  
  2.     [self.chompPlayer play];  
  3. }  

執行,點一下某個圖,就會播放一個咬東西的聲音。

不過這個點選播放聲音有點缺陷,就是在慢慢拖動的時候也會播放。這使得兩個手勢重合了。怎麼解決呢?使用手勢的:requireGestureRecognizerToFail方法。

10、手勢的依賴性

在viewDidLoad的迴圈裡新增這段程式碼:

  1. [tapRecognizer requireGestureRecognizerToFail:panGestureRecognizer];  
意思就是,當如果pan手勢失敗,就是沒發生拖動,才會出發tap手勢。這樣如果你有輕微的拖動,那就是pan手勢發生了。tap的聲音就不會發出來了。

11、自定義手勢

自定義手勢繼承:UIGestureRecognizer,實現下面的方法:

  1. – touchesBegan:withEvent:  
  2. – touchesMoved:withEvent:  
  3. – touchesEnded:withEvent:  
  4. - touchesCancelled:withEvent:  

新建一個類,繼承UIGestureRecognizer,程式碼如下:

.h檔案

  1. #import <UIKit/UIKit.h>
  2. typedefenum {  
  3.     DirectionUnknown = 0,  
  4.     DirectionLeft,  
  5.     DirectionRight  
  6. } Direction;  
  7. @interface HappyGestureRecognizer : UIGestureRecognizer  
  8. @property (assign) int tickleCount;  
  9. @property (assign) CGPoint curTickleStart;  
  10. @property (assign) Direction lastDirection;  
  11. @end  
.m檔案
  1. #import "HappyGestureRecognizer.h"
  2. #import <UIKit/UIGestureRecognizerSubclass.h>
  3. #define REQUIRED_TICKLES        2
  4. #define MOVE_AMT_PER_TICKLE     25
  5. @implementation HappyGestureRecognizer  
  6. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {  
  7.     UITouch * touch = [touches anyObject];  
  8.     self.curTickleStart = [touch locationInView:self.view];  
  9. }  
  10. - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {  
  11. 相關推薦

    iOS手勢識別詳細使用(,,旋轉,,手勢依賴,定義手勢)

    1、UIGestureRecognizer介紹手勢識別在iOS上非常重要,手勢操作移動裝置的重要特徵,極大的增加了移動裝置使用便捷性。iOS系統在3.2以後,為方便開發這使用一些常用的手勢,提供了UIGestureRecognizer類。手勢識別UIGestureRecogn

    Touch.js 手勢 旋轉!!!

    <!DOCTYPE html> <html lang=""> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="

    WPF無邊框視窗滑鼠大小

    通常,我們會 通過AllowsTransparency=”True”、 WindowStyle=”None” 這兩個屬性將wpf視窗的邊框去掉,由於邊框沒了,我們就不能通過滑鼠指標懸停在某一邊上拖動改變視窗的大小,此時若要能調整視窗大小,官方倒也提供了個屬性:R

    微信小程式仿照微信圖片和擷取頭像

    效果圖 整體思路: 實現圖片的縮放和拖動; 在圖片上方蓋上中間鏤空的半透明遮罩; 根據擷取方框區域的圖片。截圖時,在方框區域將擷取的圖片繪製出來,然後使用wx.canvasToTempFilePath擷取圖片。 實現過程和遇到的問題:

    Android定義內容,控制元件製作(可RelativeLayout定製)

    先上效果圖: 一.     製作此控制元件的起源 專案需要一個可以拖動的控制元件,在網上可以找到很多例子,有圖片拖動控制元件,有textview拖動控制元件。但是專案中需要控制元件同時可以動態通過手指調整尺寸,並且控制元件的內容不固定,需要自定義內容,即可以新增任意內容

    一個可以隨手勢的EditText,更改內容,附帶解決軟鍵盤遮擋終極方法

    慣例先來看效果圖: 最近產品同學的需求,要求定製一個可拖拽可編輯的文字,原本覺得還挺簡單,不就是寫個EditText處理一下touch事件麼,後來做了發現還有些小坑,記錄一下,順便給大家做個參考。 試錯 首先我嘗試自定義一個EditText,重寫o

    手指小球移動,空白處,小球不跟著移動

    package com.example.xxx.circle; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import and

    自己動手搞一個滑塊,水波紋效果

    window.onload = function() { var lineDiv = document.getElementById('lineDiv'); //長線條 var minDiv = document.getElementById('minDiv'); //小方塊

    定義Imageview控制元件實現多種手勢操作 (、水平、豎直、等比例、雙擊、長按)

    專案中需要使用自定義控制元件的多種手勢操作,之前在網上查閱資料的時候發現能找到的一般是隻實現了其中的幾種,這次就把我做的控制元件分享一下,人人為我,我為人人嘛,哈哈! 這個自定義控制元件實現的主要功能是控制元件的拖動和縮放(注意:不是對控制元件中的圖片進行操作,話說很多帖子

    系列(三):一個可以手勢拽、旋轉的layout

    弄了一個下午,終於搞出來了,PowerfulLayout 下面是一個功能強大的改造的例子: 可以實現以下需求: 1.兩個手指進行縮放佈局 2.所有子控制元件也隨著縮放, 3.子控制元件該有的功能不能丟失(像button有可被點選的功能,縮放後不能丟失該功能)

    iOS圖片新增平移//旋轉多個手勢

    // // UIImageView+Utils.h // OpenWorkr // // Created by 冰涼的枷鎖 on 2017/3/6. // Copyright © 2017年 Eden. All rights reserved. //

    Swift基礎--手勢識別(雙擊、捏、旋轉、划、長按)

    // // ViewController.swift // JieUITapGestureRecognizer // // Created by jiezhang on 14-10-4. // Copyright (c) 2014年 jiezhang. All rig

    vue-draggable-resizable 插件

    default () fault sel ali call ets bsp tor 安裝: npm install --save vue-draggable-resizable 使用: <template> <div style="height: 5

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style>

    Android 手勢檢測實戰 打造支援平移的圖片預覽效果(上)

                    轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/39474553,本文出自:【張鴻洋的部落格】1、背景現在app中,圖片預覽功能肯定是少不了的,使用者基本已經形成條件反射,看到小圖,點選看大圖,看到大圖兩個手指

    Android 過載ImageView 可以使用手勢放大縮小

    一 JAVA import android.content.Context; import android.graphics.Matrix; import android.graphics.PointF; import android.util.AttributeSet;

    [Swift通天遁地]三、手勢與圖表-(2)監聽手勢事件自由影象檢視

    本文將演示監聽手勢事件,使圖片可以自由被拖動。 在專案導航區,開啟檢視控制器的程式碼檔案【ViewController.swift】 現在開始編寫程式碼,實現監聽手勢事件自由拖動的影象檢視。 1 import UIKit 2 3 class ViewController: UIView

    div/dom元素外掛,純js實現,不依賴jQuery~

    產品需求,需要用到對div(dom)進行拖拽縮放操作,看到有好多外掛,要麼依賴jQuery,要麼檔案太大。 封裝了一個外掛,不壓縮狀態下5KB。 html <!DOCTYPE html> <html lang="en"> <head> <

    iOS開發之UIImage等比

    評論功能真不錯 評論開通後,果然有很多人吐槽。謝謝大家的支援和關愛,如果有做的不到的地方,還請海涵。畢竟我一個人的力量是有限的,我會盡自己最大的努力大家準備一些乾貨。 有些內容可能都是比較基礎的,記住:不積跬步無以至千里,不積小流無以成江海。我想這個道理大家都懂,在為大家準備文章的過程中,對我來說也是一次

    IOS CGAffineTransform 用於檢視平移,旋轉

    今天碰到了一個旋轉放縮圖片的一個demo,在看的過程中發現實現圖片變化的那個方法特別簡單。一共只有三句話,下面就是這個方法- (void)transformImageView{CGAffineTransform t = CGAffineTransformMakeScale(