在iOS中,UIEvent類表示當事件發生時系統收集相關的事件信息,當我們創建UIEvent對象后,對事件轉發到應用程序上,下面是武林技術小編淺析iOS之FirstResponder的介紹。
1. UIResonder
對于C#里所有的控件(例如TextBox),都繼承于Control類。而Control類的繼承關系如
下:
?
? System.MarshalByRefObject
??? System.ComponentModel.Component
????? System.Windows.Forms.Control
對于iOS里的UI類,也有類似的繼承關系。
?
例如對于UITextField,繼承于UIControl;UIControl繼承于UIView,UIView繼承于UIRe
sponder,UIResponder繼承于NSObject。
具體架構可以參見:
http://developer.apple.com/library/ios/#documentation/general/conceptual/Devp
edia-CocoaApp/Responder.html
UIResponder是UIKit框架中的類(Mac OS X Cocoa對應的是AppKit框架)。
?
2. 第一響應對象
在應用的響應對象里,會有一個成為第一響應對象。
第一響應對象和其他響應對象之間有什么區別?對于普通的觸摸事件沒什么區別。就算
我把一個按鈕設置成第一響應對象,當我點擊其他按鈕時,還是會響應其他按鈕,而不
會優先響應第一響應對象。
第一響應對象的區別在于負責處理那些和屏幕位置無關的事件,例如搖動。
蘋果官方文檔的說法是:第一響應對象是窗口中,應用程序認為最適合處理事件的對象
。
一個班只能有一個班長,應用的響應對象中,只能有一個響應對象成為第一響應對象。
?
3. 成為與取消第一響應對象。
要當第一響應對象,還需要有View來毛遂自薦:
?
如果缺少了這段,就算用[view becomeFirstResponder]也不能讓一個view成為第一響應
對象。。。強扭的瓜不甜?好吧不是這個原因。大多數視圖默認只關心與自己有關聯的
事件,并且(幾乎)總是有機會來處理這些事件。以UIButton為例,當用戶單擊某個UIB
utton對象時,無論當前的第一響應對象是哪個視圖,該對象都會收到指定的動作消息。
當上第一響應對象吃力不討好么。。。所以只能由某個UIResponder明確表示自己愿意成
為第一響應對象才行。(我不知道設計上是基于什么考慮。。。安全?)
?
在當上第一響應對象時,不同對象可能會有一些特殊的表現。例如UITextField當上的時
候,就會調出一塊小鍵盤。
第一響應對象也有可能被辭退。發送一個resignFirstResponder,就可以勸退。
?
4. 第一響應對象的任務
剛才說了第一響應對象可以處理搖動。就來看個范例吧:
?
?
當搖動開始時觸發某些行為。
?
5. 獲取當前第一響應對象
源自這篇討論:http://stackoverflow.com/questions/1823317/get-the-current-firs
t-responder-without-using-a-private-api
提問的家伙用了如下的方式來獲取
結果被蘋果打回來,說用了非公開的API。。。
?
于是這家伙只好苦逼地用遞歸了:
?
6.View的FirstResponder的釋放問題
今天遇到一個問題,當我隱藏掉一個正在接受用戶輸入的UITextField的時候,鍵盤并不會消失,而且鍵盤仍然接受用戶輸入,再次顯示該TextField時候發現在隱藏狀態下,所有的輸入仍然傳輸到了該TextField中,于是查下官方資料找到如下解釋:
?
Important If you hide a view that is currently the first responder, the view does not automatically resign its first responder status. Events targeted at the first responder are still delivered to the hidden view. To prevent this from happening, you should force your view to resign the first responder status when you hide it.???
?
意思是如果這個View是當前的第一響應者的時候,隱藏該View并不會自動放棄其第一響應者的身份,而且會繼續以第一響應者的身份接受消息。我們可以通過在隱藏View之前,手動調用resignFirstResponder來強制該view放棄第一響應者身份。
?
下面請看小例子:
?
//
//? SvTestFirstResponder.h
//
//? Created by maple on 3/15/12.
//? Copyright (c) 2012 SmileEvday. All rights reserved.
//
//? 當一個view時當前響應者時,調用其hidden方法并不會自動放棄第一響應者身份,所有的消息仍然會發送到這個view
//? 可以通過在hidden前強制放棄第一響應者,恢復正常的消息傳遞
//
#import
?
@interface SvTestFirstResponder : UIView {
??? UITextField *_inputField;
}
@end
?
?
?
//
//? SvTestFirstResponder.m
//
//? Created by maple on 3/15/12.
//? Copyright (c) 2012 SmileEvday. All rights reserved.
//
#import "SvTestFirstResponder.h"
@interface SvTestFirstResponder()
- (void)hiddenInputView:(id)sender;
- (void)showInputView:(id)sender;
@end
@implementation SvTestFirstResponder
- (id)initWithFrame:(CGRect)frame
{
??? self = [super initWithFrame:frame];
??? if (self) {
??????? // Initialization code
???????
??????? _inputField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 200, 50)];
??????? _inputField.center = CGPointMake(160, 50);
??????? [_inputField setFont:[UIFont systemFontOfSize:24]];
??????? _inputField.text = @"input you text";
??????? _inputField.clearsOnBeginEditing = YES;
??????? _inputField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
??????? _inputField.borderStyle = UITextBorderStyleRoundedRect;
??????? [self addSubview:_inputField];
??????? _inputField.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
???????
??????? UIButton *hiddenBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
??????? hiddenBtn.frame = CGRectMake(0, 0, 115, 40);
??????? hiddenBtn.center = CGPointMake(80, 110);
??????? [hiddenBtn setTitle:@"Hide TextField" forState:UIControlStateNormal];
??????? [hiddenBtn addTarget:self action:@selector(hiddenInputView:) forControlEvents:UIControlEventTouchUpInside];
??????? [self addSubview:hiddenBtn];
??????? hiddenBtn.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
??????? hiddenBtn.titleLabel.lineBreakMode = UILineBreakModeTailTruncation;
???????
??????? UIButton *showBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
??????? showBtn.frame = CGRectMake(0, 0, 115, 40);
??????? showBtn.center = CGPointMake(240, 110);
??????? [showBtn setTitle:@"Show TextField" forState:UIControlStateNormal];
??????? [showBtn addTarget:self action:@selector(showInputView:) forControlEvents:UIControlEventTouchUpInside];
??????? [self addSubview:showBtn];
??????? showBtn.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
??????? showBtn.titleLabel.lineBreakMode = UILineBreakModeTailTruncation;
??? }
??? return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
??? // Drawing code
}
*/
- (void)hiddenInputView:(id)sender
{
??? _inputField.hidden = YES;
}
- (void)showInputView:(id)sender
{
??? _inputField.hidden = NO;
}
@end
?
這個簡單的例子中,當輸入框進入接受用戶輸入狀態的時候,點擊hide按鈕,鍵盤并不會消失而且會繼續接收用戶輸入并且將用戶輸入傳到TextField中去,后面再點擊Show按鈕的時候你會發現所有在隱藏狀態下輸入的文字都已經成功的被接收。我們可以修改hide方法如下:
?
?
{
??? if (_inputField.isFirstResponder) {
??????? [_inputField resignFirstResponder];
??? }
??? _inputField.hidden = YES;
}
以上代碼都是武林技術頻道小編和大家分享的淺析iOS之FirstResponder的介紹,希望對大家的學習有一定的幫助!
新聞熱點
疑難解答