国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

iOS中—觸摸事件詳解及使用

2019-11-14 18:34:47
字體:
供稿:網(wǎng)友

iOS中——觸摸事件詳解及使用

(一)初識

要想學(xué)好觸摸事件,這第一部分的基礎(chǔ)理論是必須要學(xué)會的,希望大家可以耐心看完。

1、基本概念:

觸摸事件 是iOS事件中的一種事件類型,在iOS中按照事件劃分還可以分出另外兩類:加速計事件和遠程控制事件,我們現(xiàn)在只學(xué)習(xí)一下觸摸事件,也是iOS中最常用的事件。

注意:我們并不是可以隨意給任何對象添加觸摸事件,只可以給 響應(yīng)者對象添加,響應(yīng)者對象是指繼承自UIResponder的對象。
所以我們可以給UIView、UIapplication、UIViewController添加,因為它們都是響應(yīng)者對象。

2、UIView的觸摸事件函數(shù)

重寫下面幾個系統(tǒng)函數(shù)實現(xiàn)相應(yīng)操作:

一根或者多根手指開始觸摸view,系統(tǒng)會自動調(diào)用view的下面方法- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event一根或者多根手指在view上移動,系統(tǒng)會自動調(diào)用view的下面方法(隨著手指的移動,會持續(xù)調(diào)用該方法)- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event一根或者多根手指離開view,系統(tǒng)會自動調(diào)用view的下面方法- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event觸摸結(jié)束前,某個系統(tǒng)事件(例如電話呼入)會打斷觸摸過程,系統(tǒng)會自動調(diào)用view的下面方法- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event提示:touches中存放的都是UITouch對象

這些函數(shù)里都有NSSet *touchesUIEvent *event兩個參數(shù),下面先分別介紹一下,然后再接著學(xué)習(xí)上面幾個函數(shù)的使用

2.1、函數(shù)參數(shù)介紹

UITouch

  • 當(dāng)用戶用一根手指觸摸屏幕時,會創(chuàng)建一個與手指相關(guān)聯(lián)的UITouch對象

  • 一根手指對應(yīng)一個UITouch對象

  • UITouch的作用:
    保存著跟手指相關(guān)的信息,比如觸摸的位置、時間、階段

  • 當(dāng)手指移動時,系統(tǒng)會更新同一個UITouch對象,使之能夠一直保存該手指在的觸摸位置

  • 當(dāng)手指離開屏幕時,系統(tǒng)會銷毀相應(yīng)的UITouch對象

UITouch的屬性:

//觸摸產(chǎn)生時所處的窗口@PRoperty(nonatomic,readonly,retain) UIWindow    *window;//觸摸產(chǎn)生時所處的視圖@property(nonatomic,readonly,retain) UIView      *view;//短時間內(nèi)點按屏幕的次數(shù),可以根據(jù)tapCount判斷單擊、雙擊或更多的點擊@property(nonatomic,readonly) NSUInteger          tapCount;//記錄了觸摸事件產(chǎn)生或變化時的時間,單位是秒@property(nonatomic,readonly) NSTimeInterval      timestamp;//當(dāng)前觸摸事件所處的狀態(tài)@property(nonatomic,readonly) UITouchPhase        phase;

UITouch的方法:

//返回值表示觸摸在view上的位置//調(diào)用時傳入的view參數(shù)為nil的話,返回的是觸摸點在UIWindow的位置- (CGPoint)locationInView:(UIView *)view;
//該方法記錄了前一個觸摸點的位置- (CGPoint)previousLocationInView:(UIView *)view;

UIEvent

UIEvent:稱為事件對象,記錄事件產(chǎn)生的時刻和類型。一個事件,產(chǎn)生一個UIEvent對象。

//事件類型@property(nonatomic,readonly) UIEventType     type;@property(nonatomic,readonly) UIEventSubtype  subtype;//事件產(chǎn)生的時間@property(nonatomic,readonly) NSTimeInterval  timestamp;

2.2、觸摸事件中的參數(shù)產(chǎn)生過程

  • 一次完整的觸摸過程中,只會產(chǎn)生一個事件對象,4個觸摸方法都是同一個event參數(shù)

  • 如果兩根手指同時觸摸一個view,那么view只會調(diào)用一次touchesBegan:withEvent:方法,touches參數(shù)中裝著2個UITouch對象

  • 如果這兩根手指一前一后分開觸摸同一個view,那么view會分別調(diào)用2次touchesBegan:withEvent:方法,并且每次調(diào)用時的touches參數(shù)中只包含一個UITouch對象

  • 根據(jù)touches中UITouch的個數(shù)可以判斷出是單點觸摸還是多點觸摸

3、如何阻止UIView的觸摸事件

在下面三種情況下,UIView不接收觸摸事件,我們可以利用這一點防止一些不希望出現(xiàn)觸摸的事件發(fā)生。

  • 不接收用戶交互:

userInteractionEnabled = NO

  • 隱藏:

    hidden = YES

  • 透明

    alpha = 0.0 ~ 0.01

提示:UIImageView的userInteractionEnabled默認(rèn)就是NO,因此UIImageView以及它的子控件默認(rèn)是不能接收觸摸事件的。

4、深入理解觸摸事件的傳遞過程

理解這個過程,我們就可以做到攔截系統(tǒng)的事件傳遞,讓我們希望的View層來處理觸摸事件。做到一些特殊的需求。

4.1、觸摸事件的傳遞理論知識

首先,我們知道,觸摸事件發(fā)生在屏幕上,而在蘋果手機的屏幕之下有很多處理事件的層,依次是:

UIApplication—>UIWindow—>然后是用戶的添加的各種層或控件。

那么,當(dāng)用戶點擊了一個同時在所有層上的點之后,到底哪個層來處理這個事件呢?而這種情況幾乎到處都是。

我們做一個小例子來講解一下:

上圖中假設(shè)是一個手機屏幕,在其上面有很多圖層,數(shù)字代表圖層

的層次,在手機上的觸摸事件過程如下:

> 觸摸事件的傳遞是從父控件傳遞到子控件

  • 點擊了綠色的view:
    UIApplication -> UIWindow -> 白色 -> 綠色
  • 點擊了藍色的view:
    UIApplication -> UIWindow -> 白色 -> 橙色 -> 藍色
  • 點擊了黃色的view:
    UIApplication -> UIWindow -> 白色 -> 橙色 -> 藍色 -> 黃色

這個過程其實就是系統(tǒng)自己在尋找最合適的View來處理這個事件,

如果父控件不能接收觸摸事件,那么子控件就不可能接收到觸摸事件(掌握)

> 系統(tǒng)如何找到最合適的控件來處理事件?

  • 檢查自己是否能接收觸摸事件

  • 監(jiān)察觸摸點是否在自己身上

  • 從·后往前·遍歷子控件,重復(fù)前面的兩個步驟

  • 如果沒有符合條件的子控件,那么就自己最適合處理

系統(tǒng)的實現(xiàn)方法:

系統(tǒng)通過下面的方法實現(xiàn)上面的過程:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

驗證這個過程,我們可以通過重寫這個方法,來驗證這個過程的正確性:

// point:是方法調(diào)用者坐標(biāo)系上的觸摸點的位置- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{    // 1.判斷下能否接收觸摸事件    if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.0) return nil;    // 2.判斷下點在不在控件上    if ([self pointInside:point withEvent:event] == NO) return nil;    // 3.從后往前遍歷子控件    int count = (int)self.subviews.count;    for (int i = count - 1; i >= 0 ; i--) {        // 取出顯示在最前面的子控件        UIView *childView =  self.subviews[i];        // 轉(zhuǎn)換成子控件坐標(biāo)系上點        CGPoint childP = [self convertPoint:point toView:childView];        UIView *fitView = [childView hitTest:childP withEvent:event];        if (fitView) {            return fitView;        }    }    // 表示沒有比自己更合適的view    return self;}

> 找到最合適的視圖控件之后的處理過程

找到最合適的視圖控件后,就會調(diào)用控件的touches方法來作具體的事件處理

  • touchesBegan…
  • touchesMoved…
  • touchedEnded…

這些touches方法的默認(rèn)做法是將事件順著響應(yīng)者鏈條向上傳遞,將事件交給上一個響應(yīng)者進行處理,這個鏈條的過程一般是下面的兩種

過程如下:

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

2.
在視圖層次結(jié)構(gòu)的最頂級視圖,如果也不能處理收到的事件或消息,則其將事件或消息傳遞給window對象進行處理

3.
如果window對象也不處理,則其將事件或消息傳遞給UIApplication對象

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

二、進階

5、監(jiān)聽觸摸事件的缺點

  • 必須指定一個view。
  • 需要在view內(nèi)部的touches方法中處理監(jiān)聽事件,因此默認(rèn)情況下不能讓其他外界對象監(jiān)聽view的觸摸事件
  • 不容易區(qū)分用戶的具體手勢行為

為了解決以上的缺點,蘋果推出了手勢識別功能(Gesture Recognizer)在觸摸事件方面大大簡化了開發(fā)的難度。

為了完成手勢識別,必須借助于手勢識別器----UIGestureRecognizer

UIGestureRecognizer是一個抽象類,定義了所有手勢的基本行為,使用它的子類才能處理具體的手勢

UITapGestureRecognizer(敲擊)UipinchGestureRecognizer(捏合,用于縮放)UIPanGestureRecognizer(拖拽)UISwipeGestureRecognizer(輕掃)UIRotationGestureRecognizer(旋轉(zhuǎn))UILongPressGestureRecognizer(長按)

每一個手勢識別器的用法都差不多,比如UITapGestureRecognizer的使用步驟如下:

創(chuàng)建手勢識別器對象

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];

設(shè)置手勢識別器對象的具體屬性

// 連續(xù)敲擊2次tap.numberOfTapsRequired = 2;// 需要2根手指一起敲擊tap.numberOfTouchesRequired = 2;添加手勢識別器到對應(yīng)的view上[self.iconView addGestureRecognizer:tap];監(jiān)聽手勢的觸發(fā)[tap addTarget:self action:@selector(tapIconView:)];

實例

效果圖:

上圖展示了在一個UIImageView上面直接添加多個手勢的例子。彌補了用觸摸方法必須自定義view的缺點。而且實現(xiàn)方法顯得更加簡單。主要代碼如下:

////  ViewController.m//  手勢////  Created by 薛銀亮 on 13/7/11.//  Copyright (c) 2013年 薛銀亮. All rights reserved.//#import "ViewController.h"@interface ViewController ()<UIGestureRecognizerDelegate>@property (weak, nonatomic) IBOutlet UIImageView *imageView;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]init];    [pinch addTarget:self action:@selector(pinch:)];    pinch.delegate = self;    [_imageView addGestureRecognizer:pinch];    UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc]init];    [rotation addTarget:self action:@selector(rotation:)];    rotation.delegate = self;    [_imageView addGestureRecognizer:rotation];    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]init];    [_imageView addGestureRecognizer:tap];    [tap addTarget:self action:@selector(tap:)];}//代理方法,同時實現(xiàn)多個觸摸手勢-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{    return YES;}//旋轉(zhuǎn)-(void)rotation:(UIRotationGestureRecognizer *)rotation{    _imageView.transform = CGAffineTransformRotate(_imageView.transform, rotation.rotation);    rotation.rotation = 0;}-(void)tap:(UITapGestureRecognizer *)tap{    NSLog(@"ddd");}//捏合手勢-(void)pinch:(UIPinchGestureRecognizer *)pinchGestureRecognizer{    CGFloat scale = pinchGestureRecognizer.scale;    _imageView.transform = CGAffineTransformScale(_imageView.transform, scale, scale);    pinchGestureRecognizer.scale = 1;}@end

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 阳西县| 金阳县| 阜城县| 高唐县| 大丰市| 陆丰市| 东城区| 宝应县| 顺昌县| 永顺县| 嘉峪关市| 桦南县| 德钦县| 蒙自县| 大方县| 邵阳县| 郑州市| 正蓝旗| 洛隆县| 威宁| 达州市| 宜兴市| 蒲城县| 唐山市| 平远县| 万宁市| 鄯善县| 页游| 永和县| 乐安县| 开封市| 克东县| 木兰县| 会泽县| 来宾市| 奉化市| 汉中市| 周至县| 周至县| 望城县| 内乡县|