UITextField
- (void)loadView
{
CGRect frame = [UIScreen mainScreen].bounds;
BNRHypnosisView *backgroundView = [[BNRHypnosisView alloc] initWithFrame:frame];
CGRect textFieldRect = CGRectMake(40, 70, 240, 30);
UITextField *textField = [[UITextField alloc] initWithFrame:textFieldRect];
// Setting the border style on the text field will allow us to see it more easily
textField.borderStyle = UITextBorderStyleRoundedRect;
[backgroundView addSubview:textField];
self.view = backgroundView;
}
UIResponder
UIResponder is an abstract class in the UIKit framework. It is the superclass of three classes that you have already encountered:
- UIView
- UIViewController
- UIApplication
UIResponder是個(gè)抽象類,UIView,UIViewController和UIApplication都實(shí)現(xiàn)了此類。
UIResponder defines methods for handling (or “responding to”) events: touch events, motion events (like a shake), and remote control events (like pausing or playing). Subclasses override these methods to customize how they respond to events.
UIResponder定義了事件響應(yīng)方法,響應(yīng)touch, motion, remote control事件,其子類可以重寫這些事件響應(yīng)方法。
With touch events, it is obvious which view the user has touched. Touch events are sent directly to that view.
What about the other types of events? The UIWindow has a pointer called firstResponder which indicates who should respond to the other types of events. When you select a text field, for example, the window moves its firstResponder pointer to that text field. Motion and remote control events are sent to the first responder.
touch事件會(huì)直接發(fā)送給被觸摸的視圖。
UIWindow中有個(gè)指針叫firstResponder,來指明誰來響應(yīng)motion, remote control事件。當(dāng)選中一個(gè)text field,firstResponder指針會(huì)指向這個(gè)text field。
When a text field or a text view becomes firstResponder, it shows its keyboard. When it loses first responder status, it hides its keyboard. If you want one of these views to become first responder, you send it the message becomeFirstResponder and the keyboard appears. When you want to hide the keyboard, you send it the message resignFirstResponder.
當(dāng)text filed變成firstResponder,會(huì)顯示鍵盤,當(dāng)其不再是firstResponder,鍵盤隱藏。
如果想讓某視圖變成firstResponder,可以調(diào)用該視圖的becomeFirstResponder,反之調(diào)用resignFirstResponder。
Keyboard
The keyboard’s appearance is determined by a set of the UITextField’s properties called UITextInputTraits.
| property | description |
|---|---|
| autocapitalizationType | This determines how capitalization is handled. The options are none, words, sentences, or all characters. |
| autocorrectionType | This will suggest and correct unknown words. This value can be YES or NO. |
| enablesReturnKeyAutomatically | This value can be YES or NO. If set to yes, the return key will be disabled if no text has been typed. As soon as any text is entered, the return key becomes enabled. |
| keyboardType | This determines the type of keyboard that will be displayed. Some examples are the ASCII keyboard, email address keyboard, number pad, and the URL keyboard. |
| secureTextEntry | Setting this to YES makes the text field behave like a password field, hiding the text that is entered. |
- (void)loadView
{
CGRect frame = [UIScreen mainScreen].bounds;
BNRHypnosisView *backgroundView = [[BNRHypnosisView alloc] initWithFrame:frame];
CGRect textFieldRect = CGRectMake(40, 70, 240, 30);
UITextField *textField = [[UITextField alloc] initWithFrame:textFieldRect];
// Setting the border style on the text field will allow us to see it more easily
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.placeholder = @"Hypnotize me";
// 設(shè)置鍵盤的retrun key type為Done
// 鍵盤的return key:鍵盤輸入完成后,點(diǎn)擊return key完成輸入,隱藏鍵盤
textField.returnKeyType = UIReturnKeyDone;
[backgroundView addSubview:textField];
self.view = backgroundView;
}
Delegation pattern
You have already seen the Target-Action pattern. This is one form of callbacks that is used by UIKit: When a button is tapped, it sends its action message to its target.
A button’s life is relatively simple. For objects with more complex lives, like a text field, Apple uses the delegation pattern.
代理模式,為UITextField對(duì)象設(shè)置代理,由代理來處理UITextField的各種消息。
代理要為text filed對(duì)象實(shí)現(xiàn)的一些方法如下:
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField;
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField;
- (BOOL)textFieldShouldClear:(UITextField *)textField;
- (BOOL)textFieldShouldReturn:(UITextField *)textField;
設(shè)置text filed的delegate屬性,指定其代理
// BNRHypnosisViewController
- (void)loadView
{
CGRect frame = [UIScreen mainScreen].bounds;
BNRHypnosisView *backgroundView = [[BNRHypnosisView alloc] initWithFrame:frame];
CGRect textFieldRect = CGRectMake(40, 70, 240, 30);
UITextField *textField = [[UITextField alloc] initWithFrame:textFieldRect];
// Setting the border style on the text field will allow us to see it more easily
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.placeholder = @"Hypnotize me";
// 設(shè)置鍵盤的retrun key type為Done
textField.returnKeyType = UIReturnKeyDone;
// 為text filed設(shè)置delegate
textField.delegate = self;
[backgroundView addSubview:textField];
self.view = backgroundView;
}
Protocol
代理需要為被代理對(duì)象實(shí)現(xiàn)哪些方法呢?這由protocol來定義,protocol就像JAVA中的接口。
The protocol for UITextField’s delegate looks like this:
// The NSObject in angled brackets refers to the NSObject protocol and tells us
// that UITextFieldDelegate includes all of the methods in the NSObject protocol.
@protocol UITextFieldDelegate <NSObject>
@optional
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField;
- (void)textFieldDidBeginEditing:(UITextField *)textField;
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField;
- (void)textFieldDidEndEditing:(UITextField *)textField;
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
- (BOOL)textFieldShouldClear:(UITextField *)textField;
- (BOOL)textFieldShouldReturn:(UITextField *)textField;
@end
Note that a protocol is not a class; it is simply a list of method declarations.
Methods declared in a protocol can be required or optional. By default, protocol methods are required. If a protocol has optional methods, these are preceded by the directive @optional.
Before sending an optional message, the object first asks its delegate if it is okay to send that message by sending another message, respondsToSelector:. Every object implements this method, which checks at runtime whether an object implements a given method. You can turn a method selector into a value that you can pass as an argument with the @selector() directive. For example, UITextField could implement a method that looks like this:
- (void)clearButtonTapped
{
// textFieldShouldClear: is an optional method, so we check first
SEL clearSelector = @selector(textFieldShouldClear:);
// 先檢查對(duì)應(yīng)的方法是否存在,如果存在再調(diào)用
if ([self.delegate respondsToSelector:clearSelector]) {
if ([self.delegate textFieldShouldClear:self]) {
self.text = @"";
}
}
}
protocol不是一個(gè)類,只是聲明了一些抽像方法。
protocol中的方法默認(rèn)是required,就是代理必須要實(shí)現(xiàn)的;可以用@optional來聲明為可選的。
被代理的對(duì)象在調(diào)用protocol中聲明的optional方法前,會(huì)先通過respondsToSelector:方法來確認(rèn)代理是否實(shí)現(xiàn)了對(duì)應(yīng)的optional message(OC中叫message,可以理解為java中的method)。
**
對(duì)象,代理(delegate),協(xié)議(protocol),這三者的關(guān)系要理清楚:對(duì)象(比如一個(gè)text field)有一個(gè)對(duì)應(yīng)的protocol,用來定義text field對(duì)象的delegate應(yīng)該實(shí)現(xiàn)的方法,delegate要去實(shí)現(xiàn)protocol中定義的方法。text field對(duì)象會(huì)去調(diào)用delegate中實(shí)現(xiàn)的方法。
**
But for the compiler to know to check for implementations of a protocol’s required methods, the class must explicitly state that it conforms to a protocol. This is done either in the class header file or the class extension: the protocols that a class conforms to are added to a comma-delimited list inside angled brackets in the interface declaration.
delegate要標(biāo)明實(shí)現(xiàn)哪些protocol,可以頭文件或是在class extension中聲明實(shí)現(xiàn)的protocol,用尖括號(hào)括起來,如果有多個(gè)protocol用逗號(hào)分隔。
在頭文件和class extension中的區(qū)別如之前講到的,頭文件中的是public的,class extension中的是private的。
The reason for adding it to the class extension rather than the header file is the same reason as always: add to the class extension if the information (conforming to a particular protocol in this case) does not need to be publicly visible, and add it to the header file if other objects do need to know about the information.
以下是在class extension中標(biāo)明:
@interface BNRHypnosisViewController () <UITextFieldDelegate>
@end
Motion Effects
蘋果設(shè)備上,在首頁傾斜屏幕,可以看到首頁的圖標(biāo)會(huì)移動(dòng)。這可以通過UIInterpolatingMotionEffect來實(shí)現(xiàn):
UIInterpolatingMotionEffect *motionEffect;
motionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
motionEffect.minimumRelativeValue = @(-25);
motionEffect.maximumRelativeValue = @(25);
[messageLabel addMotionEffect:motionEffect];
motionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
motionEffect.minimumRelativeValue = @(-25);
motionEffect.maximumRelativeValue = @(25);
[messageLabel addMotionEffect:motionEffect];
main() and UIApplication
iOS應(yīng)用的程序入口,如下:
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([BNRAppDelegate class]));
}
}
The function UIApplicationMain creates an instance of a class called UIApplication. For every application, there is a single UIApplication instance. This object is responsible for maintaining the run loop. Once the application object is created, its run loop essentially becomes an infinite loop: the executing thread will never return to main().
UIApplicationMain 方法創(chuàng)建了一個(gè) UIApplication 實(shí)例,一個(gè)應(yīng)用只有一個(gè)此實(shí)例,負(fù)責(zé)維護(hù)應(yīng)用的run loop。
Another thing the function UIApplicationMain does is create an instance of the class that will serve as the UIApplication’s delegate. Notice that the final argument to the UIApplicationMain function is an NSString that is the name of the delegate’s class. So, this function will create an instance of BNRAppDelegate and set it as the delegate of the UIApplication object.
UIApplicationMain 方法不僅創(chuàng)建了UIApplication 實(shí)例,還會(huì)為其創(chuàng)建對(duì)應(yīng)的delegate,UIApplicationMain 方法的最后一個(gè)參數(shù)就是delegate's name。
The first event added to the run loop in every application is a special “kick-off” event that triggers the application to send a message to its delegate. This message is application:didFinishLaunchingWithOptions:. You implemented this method in BNRAppDelegate.m to create the window and the controller objects used in this application.
然后application調(diào)用其代理的application:didFinishLaunchingWithOptions:方法來完成窗口及相應(yīng)視圖的創(chuàng)建,我們?cè)诖朔椒ㄌ砑幼约旱囊晥D。
本文是對(duì)《iOS Programming The Big Nerd Ranch Guide 4th Edition》第七章的總結(jié)。