[apple文檔]事件編程指南

來源:互聯網
上載者:User
一.事件的類型和傳遞

1.UIEventType(Touches,Motion,RemoteControl),UIEventSubType,

2.touch event的路由規則:touchTest,pointInside:withEvent.

以下是我的一些分析:可能有出入

baseView中連續添加viewA,viewB,viewC,viewA中添viewD,viewD中添加viewE;

先測試hittest:

例子A:viewA,viewB,viewC都實現了 hittest,假設直接返回self,則點擊baseView任何地方,則響應viewC,因為是第一層的最上層,如果viewC的hittest返回nil,則傳遞給viewB,則viewB響應,以此類推。當然你可以再對應方法中調用super hitTest方法,這樣的話就是系統預設的方式去判斷返回的view是哪個,如果不實現pointInView,則是返回點中的view.順便說一句,如果baseView實現hitTest並且返回self,則直接響應baseView了,返回nil,則結束了,不會去自動尋找下層。hitTest是先尋找當前層,再尋找下一層的。此外假設viewA超過了baseView,則點擊baseView外地方,則沒有任何響應。點擊viewA也是。

例子B:viewA,viewB,viewC都實現 hitTest並調用super hitTest或者乾脆就不實現,viewD,viewE實現了pointInside方法,當viewD返回true時,則viewE也會觸發以此pointInside方法,如果返回YES,則viewE觸發touch,返回NO,則viewD觸發touch,如果viewD方法中返回NO,則viewA觸發了touch。

結論1:調用super hitTest其實就是按照事件傳遞的基本規則去尋找事件的響應者,在你自己實現了的方法中不調用super方法,則不會去傳遞到下一層,所以當baseView實現hitTest但是返回nil則沒有調用subview的hittest,但是如果viewC返回nil,則還會調用viewB,因為當baseView沒有實現hitTest方法時,則會預設執行[super hittest].

結論2:pintInside和hitTest傳遞的方式都是從上層傳遞到下層的捕獲方式的傳遞,當pointInside返回yes,則會判斷其子view是否返回yes,如果有,則再繼續尋找,直到都返回no,或者返回yes,並且已經是最後一層,才能確定該view是觸發view.而hitTest則是調用super hitTest方法來觸發這樣的傳遞,如果你返回的view不是你想要的view,還可以決定其他view來作為觸發的view,反正最後關鍵是看方法返回的是哪個UIView作為觸發對象。

3.first responder是指第一個處理應用事件的對象(通常是UIView),這些事件不僅僅是touch事件

a)Motion events

b)remote-control events

c)Action messages:使用者在應用中建立了一個control(button或者slider),並且沒有為其指定target.

d)editing-menu message:

e)text-editing:UIKit會自動將text field或者text view 設定成first responder

二.多觸摸事件

1.UIEvent提供了整個事件程序中的touch事件

a)allTouches

b)touchesForWindow:返回針對某個window的touch對象

c)touchesForView:返回針對某個view的touch對象

2.UITouch某個touch事件

a)anyObject:返回一個touch對象,NSSet是一個無序的集合,他是用hashcode來儲存資料的,不同於NSArray

b)locationInView,previousLocationView:傳遞self的話,則是返回這個view中的位置

c)tapCount:

d)timstamp

3.touch相關的一些方法

a)userInteractionEnabled

b)UIApplication的beginIgnoringInteractionEvents和endIgnoringInteractionEvents

c)multipleTouchEnabled

d)exclusiveTouch

e)hitTest:withEvent來限制多點觸摸事件

4.處理複雜的多觸摸事件

a)multipleTouchEnabled=YES

b)要用Core Foundation Dictionary (CFDictionaryRef)來跟蹤touches以你為UITouch是沒有遵循NSCopying協議,所以不能使用NSDictionary

if ([touches count] > 0) {        for (UITouch *touch in touches) {            CGPoint *point = (CGPoint *)CFDictionaryGetValue(touchBeginPoints, touch);            if (point == NULL) {                point = (CGPoint *)malloc(sizeof(CGPoint));                CFDictionarySetValue(touchBeginPoints, touch, point);            }            *point = [touch locationInView:view.superview];        }    }

從touchBeginPoints查看是否有touch為key的value,如果沒有,則建立它,然後在touch上設定該point指標,注意這個是指標,真正賦值的是*point=[touch……],注意給賦值的時候是需要加一個*來賦值。

5.如何判斷多觸摸事件的結束

- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {    if ([touches count] == [[event touchesForView:self] count]) {        // last finger has lifted....    }}

6.轉寄touch events,sendEvent(這個可能需要進一步擷取資料)

7.其他一些注意點有助於處理觸摸事件

a)總是實現event-cancel method,因為你的真箇觸摸事件流程中可能都會遇到cancel的情況,比方說接到一個郵件或者call.你所要做的就是恢複之前的狀態

b)如果你的event方法是是現在一個UIView,UIViewController或者很少見的UIResponder的子類的話,你需要實現所有touch方法,不要調用super方法

如果是其他UIKit responder class,比如UIImageView,UISlider,則不用實現所有touch方法,但是需要調用super對應的方法

c)不要往其它UIKit架構對象轉寄事件,而是只有你自己的custom View of UIView

d)所有事件方法中不要涉及繪製部分,只需要標記狀態,所有繪製代碼應該讓drawRect來協助實現

三.手勢

1.在發送touch事件的結束階段(Ended Phase)到hit-test view前,window對象會將它發送到手勢辨識器所涉及的view及其subviews

2.locationInView:和locationOfTouch:inView

3.處理多個手勢並存的情況

a)接受另外一個手勢前需要另外一個手勢失敗:

比如說單擊手勢是需要雙擊手勢確定失敗後才執行:[singleTap requireGestureRecognizerToFail:doubleTap];

b)通過分析多觸摸touch事件來阻止某些手勢辨識器

UIGestureRecognizerDelegate裡

gestureRecognizerShouldBegin:當一個手勢辨識器準備將狀態標識為UIGestureRecognizerStatePossible前調用,如果返回NO,則標記為失敗

gestureRecognizer:shouldReceiveTouch:這個方法是在window調用touchesBegan事件前調用,返回NO,可以阻止guesture接收這些touch事件

此外還有在UIGestureRecognizerSubclass.h中的2個方法類似

-(BOOL)canPreventGestureRecognizer:(UIGestureRecognizer*)preventedGestureRecognizer;

-(BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer*)preventingGestureRecognizer;

c)允許多個手勢識別

UIGestureRecognizerDelegate裡gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:

4.touches事件和手勢事件的流程

假設一個2指的操作:

a)發送2個began
phase touch事件給辨識器,但是辨識器不認,則發送給UIView.

b)發送2個move phase touch事件給辨識器,辨識器依舊無法識別,然後發給UIView.

c)一個手指離開view,發送一個touch事件給ended phase touch事件給辨識器,由於辨識器資料不夠,還是不能確認,不過這個事件被暫時阻止傳送給UIView

d)第二個手指離開,又發送了個touch事件,辨識器識別出了手勢,將狀態標記成UIGuestureRecognizerStateRecognized了,view會接受touchesCancelled:withEvent:

假設最後一步辨識器沒有識別出,則會將2個end phase touch事件發給touchesEnded:withEvent:方法

此外如果是一個連續的手勢識別,則這個狀態可能會被標識為UIGuestureRecognizerStateBegan,然後所有事件都會發送給手勢辨識器,而不發送給view了

影響事件的幾個參數:

cancelsTouchesInView(預設為YES):NO的話,手勢識別失敗的話,也不會調用cancel,那麼之前的touch事件也不會是無效的了

delaysTouchesBegan(預設為NO) 在手勢識別結束前,不會有任何手勢事件發送給view

delaysTouchesEnded(預設為YES)如果是NO,原本view接受的順序是touchesBegan,touchesEnded,touchesBegan,touchesCancelled;YES的話則是touchesBegan,touchesBegan,touchesCancelled,touchesEnded

5.建立自訂手勢識別

手勢狀態的變化(不連續的(如tap),連續的(如pan)),詳細代碼可以看Event
handling Guide或者《iphone4開發基礎》。

四.搖動事件

1.聲明是first Responder

- (BOOL)canBecomeFirstResponder {    return YES;} - (void)viewDidAppear:(BOOL)animated {    [self becomeFirstResponder];}

2.實現代理方法

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event{} - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event{    [UIView beginAnimations:nil context:nil];    [UIView setAnimationDuration:0.5];    self.view.transform = CGAffineTransformIdentity;     for (UIView *subview in self.view.subviews) {        subview.transform = CGAffineTransformIdentity;    }    [UIView commitAnimations];     for (TransformGesture *gesture in [window allTransformGestures]) {        [gesture resetTransform];    }} - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event{}

3.此外我在開發相關程式時以為這個一定要作為rootcontroller才能響應,其實不是的,假設我有一個rootViewController,然後rootViewController裡顯示了其他controller的View,那麼那個controller同樣可以成為第一響應者,只是如果該controller裡如果不實現motion方法,則會傳遞上去,那麼就會調用rootViewController的motion方法。

4.coreMotion的使用,詳細看文檔或者看《iphone4開發基礎》
大致就是使用陀螺儀,表示方向,加速記表示位移量。該類服務的使用可以分為推送和主動擷取方法。

五.遠端控制多媒體

1.聲明first responder

- (void)viewDidAppear:(BOOL)animated {    [super viewDidAppear:animated];    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];    [self becomeFirstResponder];}- (void)viewWillDisappear:(BOOL)animated {    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];    [self resignFirstResponder];    [super viewWillDisappear:animated];}

- (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {     if (receivedEvent.type == UIEventTypeRemoteControl) {         switch (receivedEvent.subtype) {             case UIEventSubtypeRemoteControlTogglePlayPause:                [self playOrStop: nil];                break;             case UIEventSubtypeRemoteControlPreviousTrack:                [self previousTrack: nil];                break;             case UIEventSubtypeRemoteControlNextTrack:                [self nextTrack: nil];                break;             default:                break;        }    }}




聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.