iOS開發學習之觸摸事件和手勢識別 – iPhone手機開發技術文章 iPhone軟體開發教學課程

iOS的輸入事件

觸摸事件

手勢識別

手機搖晃

一、iOS的輸入事件

 

觸摸事件(滑動、點擊)

運動事件(搖一搖、手機傾斜、行走),不需要人為參與的

遠程控制事件(耳機控制手機聲音)

1⃣️iOS事件對象都是UIEvent類的實例

UIEvent類對事件類型定義瞭enum常量:

typedef NS_ENUM(NSInteger, UIEventType){

     UIEventTypeTouches,

     UIEventTypeMotion,

     UIEventRemoteControl,

};

觸摸事件必須是繼承UIResponser的

二、觸摸事件

1⃣️UIView,有4種處理不同的觸摸事件

UIView是UIResponder的子類,可以覆蓋下列4個方法處理不同的觸摸事件。

1. 一根或者多根手指開始觸摸屏幕

– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

2.一根或者多根手指在屏幕上移動(隨著手指的移動,會持續調用該方法)

– (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

3.一根或者多根手指離開屏幕

– (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

4.觸摸結束前,某個系統事件(例如電話呼入)會打斷觸摸過程

– (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

復制代碼

#pragma mark – UITouch事件

#pragma mark 觸摸開始

– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    NSLog(@"觸摸開始");

    for (UITouch *touch in touches) {

        NSLog(@"%@", touch);

    }

}

 

#pragma mark 觸摸移動

– (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

{

    NSLog(@"觸摸移動Touch對象個數:%d",[touches count]);

    // 要移動界面上黃顏色的視圖

    

    // 1. 得到當前手指的位置

    UITouch *touch = [touches anyObject];

    CGPoint location = [touch locationInView:self.view];

    // 2. 得到上一次手指的位置

    CGPoint preLocation = [touch previousLocationInView:self.view];

    // 3. 計算兩個位置之間的偏移

    CGPoint offset = CGPointMake(location.x – preLocation.x, location.y – preLocation.y);

    // 4. 使用計算出來的偏移量,調整視圖的位置

    [_demoView setCenter:CGPointMake(_demoView.center.x + offset.x, _demoView.center.y + offset.y)];

    

    // 完整的UITouch事件調試方法

    NSLog(@"觸摸移動");

    for (UITouch *touch in touches) {

        NSLog(@"%@", touch);

    }

}

 

#pragma mark 觸摸結束

– (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

{

    // 完整的UITouch事件調試方法

    NSLog(@"觸摸完成");

    for (UITouch *touch in touches) {

        NSLog(@"%@", touch);

    }

}

 

#pragma mark 觸摸中斷

– (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

{

    // 完整的UITouch事件調試方法

    NSLog(@"觸摸中斷");

    for (UITouch *touch in touches) {

        NSLog(@"%@", touch);

    }

}

復制代碼

2⃣️觸摸事件的處理

如果hit-test視圖無法處理事件,則通過響應者鏈向上傳遞

1.如果hit-test視圖的控制器存在,就傳遞給控制器;如果控制器不存在,則將其傳遞給它的父視圖

2.如果視圖或它的控制器無法處理收到的事件或消息,則將其傳遞給該視圖的父視圖

3.每一個在視圖繼承樹中的上層視圖如果不能處理收到的事件或消息,則重復上面的步驟1,2

4.在視圖繼承樹的最上層視圖,如果也不能處理收到的事件或消息,則其將事件或消息傳遞給窗口對象進行處理

5. 如果窗口對象也不能進行處理,則其將事件或消息傳遞給UIApplication對象

6.如果UIApplication也不能處理該事件或消息,則將其丟棄

當用戶點擊屏幕時,會產生一個UITouch對象傳遞給UIApplication,然後由window負責查找最適合相應觸摸事件的視圖對象(hitTest,pointInside)

找到合適的視圖之後,Touch方法由對應的視圖完成,上級視圖不再接管

3⃣️不接受處理事件的三種方法

不接收用戶交互:userInteractionEnabled = NO;

隱藏:hidden = YES;

透明:alpha = 0~0.01

三、手勢識別

1⃣️iOS目前支持的手勢識別(6種)

UITapGestureRecognizer(點按)

UIPinchGestureRecognizer(捏合)

UIPanGestureRecognizer(拖動)

UISwipeGestureRecognizer(輕掃)

UIRotationGestureRecognizer(旋轉)

UILongPressGestureRecognizer(長按)

2⃣️手勢識別的使用方法(4步)

通常在視圖加載的時候定義(UIGestureRecognizer是抽象類,需要實例化使用)

創建手勢識別實例

設置手勢識別屬性,例如手指數量,方向等

將手勢識別附加到指定的視圖之上

編寫手勢觸發響應方法

3⃣️手勢識別的狀態(7個)

   1.  // 沒有觸摸事件發生,所有手勢識別的默認狀態

    UIGestureRecognizerStatePossible,

    // 一個手勢已經開始但尚未改變或者完成時

    UIGestureRecognizerStateBegan,

    // 手勢狀態改變

    UIGestureRecognizerStateChanged,

    // 手勢完成

    UIGestureRecognizerStateEnded,

    // 手勢取消,恢復至Possible狀態

    UIGestureRecognizerStateCancelled, 

    // 手勢失敗,恢復至Possible狀態

    UIGestureRecognizerStateFailed,

    // 識別到手勢識別

    UIGestureRecognizerStateRecognized =UIGestureRecognizerStateEnded 

  2.手勢識別的屬性

state——手勢狀態

view——手勢發生視圖

常用方法

locationInView 獲得手勢發生對應視圖所在位置

復制代碼

– (void)viewDidLoad

{

    [super viewDidLoad];

    /**

     1. 演示點按手勢

     */

    // 根據實例化方法,我們知道:

    // 1.有一個處理消息的對象,應該是self

    // 2.我們需要定義一個方法,當手勢識別檢測到的時候,運行

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

    // setNumberOfTapsRequired 點按次數

    [tap setNumberOfTapsRequired:1];

    // setNumberOfTouchesRequired 點按的手指數量

    [tap setNumberOfTouchesRequired:1];

    // 把手勢識別增加到視圖上

    [self.demoView addGestureRecognizer:tap];

    

    /**

     2. 捏合點按手勢

     */

    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinchAction:)];

    [self.demoView addGestureRecognizer:pinch];

    

    /**

     3. 旋轉點按手勢

     */

    UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotationAction:)];

    [self.demoView addGestureRecognizer:rotation];

    

    /**

     4. 拖放點按手勢

     */

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panAction:)];

    [self.demoView addGestureRecognizer:pan];

    

    /**

     5. 長按手勢

     */

    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPressAction:)];

    [self.demoView addGestureRecognizer:longPress];

    

    /**

     6. 輕掃手勢

     關於輕掃手勢,是需要指定方向的,如果你不指定方向,那麼隻能接收到的向右方向的輕掃事件

     */

    // 向左掃

    UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];

    [swipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];

    [self.view addGestureRecognizer:swipeLeft];

    // 向右掃

    UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];

    [swipeRight setDirection:UISwipeGestureRecognizerDirectionRight];

    [self.view addGestureRecognizer:swipeRight];

    // 向上掃

    UISwipeGestureRecognizer *swipeTop = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];

    [swipeTop setDirection:UISwipeGestureRecognizerDirectionUp];

    [self.view addGestureRecognizer:swipeTop];

    // 向下掃

    UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];

    [swipeDown setDirection:UISwipeGestureRecognizerDirectionDown];

    [self.view addGestureRecognizer:swipeDown];

}

 

– (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

 

#pragma mark – 輕掃手勢

– (void)swipeAction:(UISwipeGestureRecognizer *)sender

{

    NSLog(@"%d", sender.direction);

    switch (sender.direction) {

        case UISwipeGestureRecognizerDirectionLeft:

            NSLog(@"向左掃");

            break;

        case UISwipeGestureRecognizerDirectionRight:

            NSLog(@"向右掃");

            break;

        case UISwipeGestureRecognizerDirectionUp:

            NSLog(@"向上掃");

            break;

        case UISwipeGestureRecognizerDirectionDown:

            NSLog(@"向下掃");

            break;

        default:

            break;

    }

}

 

#pragma mark – 長按手勢

– (void)longPressAction:(UILongPressGestureRecognizer *)sender

{

    // 我們可以利用demoView的Tag屬性,默認時tag=0

    // 如果tag=0,我們放大一倍,否則,我們縮小一半

    CGFloat scale;

    if (_demoView.tag == 0) {

        scale = 2.0;

        _demoView.tag = 1;

    } else {

        scale = 0.5;

        _demoView.tag = 0;

    }

    

    sender.view.transform = CGAffineTransformScale(sender.view.transform, scale, scale);

}

 

#pragma mark – 拖放手勢

– (void)panAction:(UIPanGestureRecognizer *)sender

{

    // 在拖放手勢中是需要考慮手指的狀態的UIGestureRecognizerState

    // 在拖放手勢中使用的狀態是UIGestureRecognizerStateChanged

    // 通常在使用拖放手勢的時候,當手指離開的時候,應該做一個很小的動作,提醒用戶拖放完成

    if (sender.state == UIGestureRecognizerStateChanged) {

        // locationInView

        [_demoView setCenter:[sender locationInView:self.view]];

    } else if (sender.state == UIGestureRecognizerStateEnded) {

        [_demoView setBackgroundColor:[UIColor yellowColor]];

    }

}

 

#pragma mark – 旋轉手勢

– (void)rotationAction:(UIRotationGestureRecognizer *)sender

{

    sender.view.transform = CGAffineTransformRotate(sender.view.transform, sender.rotation);

    

    // 和捏合操作類似,旋轉角度同樣需要方福偉

    sender.rotation = 0.0f;

}

 

#pragma mark – 捏合手勢

– (void)pinchAction:(UIPinchGestureRecognizer *)sender

{

    // 有關轉換的內容,我們在後續動畫部分再繼續

    sender.view.transform = CGAffineTransformScale(sender.view.transform, sender.scale, sender.scale);

    

    // 縮放功能很簡單,但是不要忘記將比例復位

    sender.scale = 1.0f;

    NSLog(@"捏我瞭");

}

 

#pragma mark – 點按手勢

– (void)tapAction:(UITapGestureRecognizer *)sender

{

    /**

     在開發過程中,如果沒有什麼必要,最好不要對一個UI控件,既使用觸摸,又使用手勢。

     */

    NSLog(@"點我瞭 %@", sender);

}

 

#pragma mark – 手勢觸摸事件

– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    NSLog(@"觸摸事件!");

    // 1. 先取出UITouch對象

    // 2. 判斷響應點擊的UIView是不是我們需要的

    UITouch *touch = [touches anyObject];

    if ([touch view] == _imageView) {

        NSLog(@"點到圖像瞭!");

    }

}

復制代碼

四、手機搖晃

1. 新建搖晃監聽視圖ShakeListenerView,並且設置canBecomeFirstResponder返回YES

– (BOOL)canBecomeFirstResponder

{

    return YES;

}

2. 在Storyboard中將ViewController的View的Class設置為:ShakeListenerView

3. 在ViewController.m文件中增加:viewDidAppear和viewDidDisappear在視圖出現和消失時成為/撤銷第一響應者身份

4. 在視圖控制器中增加手勢監聽方法:

– (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event

{

    if (event.subtype == UIEventSubtypeMotionShake) {

        NSLog(@"shake phone");

    }

}

復制代碼

#pragma mark – 要讓ViewController支持搖晃,需要寫三個方法

// 1. 成為第一響應者,視圖一出現時,就應該成為第一響應者

– (void)viewDidAppear:(BOOL)animated

{

    [self.view becomeFirstResponder];

    // 不要忘記去實現父類方法

    [super viewDidAppear:animated];

}

 

// 2. 註銷第一響應者,視圖要關閉的時候,註銷

– (void)viewDidDisappear:(BOOL)animated

{

    [self.view resignFirstResponder];

    // 不要忘記去實現父類方法

    [super viewDidDisappear:animated];

}

 

// 3. 監聽並處理移動事件,判斷是否搖晃瞭手機

– (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event

{

    if (motion == UIEventSubtypeMotionShake) {

        NSLog(@"搖啊搖,搖到外婆橋!!!");

    }

}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *