The sequence of messages that both text views and text fields send to their delegates is as follows:
-
Just before a text object becomes first responder—
textFieldShouldBeginEditing:(text field) andtextViewShouldBeginEditing:(text view).The delegate can verify whether the text object should become first responder by returning
YES(the default) orNO. -
Just after a text object becomes first responder—
textFieldDidBeginEditing:(text field) andtextViewDidBeginEditing:(text view).The delegate can respond to this message by updating state information or, for example, by showing an overlay view during the editing session.
-
During the editing session—various.
While the user enters and edits text, the text object invokes certain delegation methods (if implemented). For example, the delegate of a text view can receive a
textViewDidChange:message when any text changes. The delegate of a text field can receive atextFieldShouldClear:message when the user taps the clear button of a text field; the delegate returns a Boolean value indicating whether the text should be cleared. -
Just before a text object resigns first responder—
textFieldShouldEndEditing:(text field) andtextViewShouldEndEditing:(text view).The primary reason for a delegate to implement these methods is to validate entered text. For example, if text should conform to a given format, the delegate validates the entered string here and returns
NOif the string does not conform. The default return value isYES.A related method for text fields is
textFieldShouldReturn:. When the user taps the return key, the text field class sends atextFieldShouldReturn:message to the delegate to ask whether it should resign first responder. -
Just after text a object resigns first responder—
textFieldDidEndEditing:(text field) andtextViewDidEndEditing:(text view).A delegate can implement these methods to get the text that the user has just entered or edited.
Using Overlay Views in Text Fields
- (void)textFieldDidBeginEditing:(UITextField *)textField {if (textField.tag == NameField && self.overlayButton) {textField.leftView = self.overlayButton;
textField.leftViewMode = UITextFieldViewModeAlways;
}
}
@dynamic overlayButton;
- (UIButton *)overlayButton {if (!overlayButton) {overlayButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
UIImage *overlayImage = [UIImage imageNamed:@"bookmark.png"];
if (overlayImage) {[overlayButton setImage:overlayImage forState:UIControlStateNormal];
[overlayButton addTarget:self action:@selector(bookmarkTapped:)
forControlEvents:UIControlEventTouchUpInside];
}
}
return overlayButton;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {if (textField.tag == NameFieldTag) {textField.leftView = nil;
}
// remainder of implementation....
}
Moving Content That Is Located Under the Keyboard
方法一:嵌套进 uiscrollview 中, 调整contentInset 底部增加为键盘高度
Adjusting your content typically involves temporarily resizing one or more views and positioning them so that the text object remains visible. The simplest way to manage text objects with the keyboard is to embed them inside a
UIScrollViewobject (or one of its subclasses likeUITableView). When the keyboard is displayed, all you have to do is reset the content area of the scroll view and scroll the desired text object into position. Thus, in response to aUIKeyboardDidShowNotification, your handler method would do the following:-
Get the size of the keyboard.
-
Adjust the bottom content inset of your scroll view by the keyboard height.
-
Scroll the target text field into view.
-
Handling the keyboard notifications
// Call this method somewhere in your view controller setup code. |
- (void)registerForKeyboardNotifications |
{ |
[[NSNotificationCenter defaultCenter] addObserver:self |
selector:@selector(keyboardWasShown:) |
name:UIKeyboardDidShowNotification object:nil]; |
| |
[[NSNotificationCenter defaultCenter] addObserver:self |
selector:@selector(keyboardWillBeHidden:) |
name:UIKeyboardWillHideNotification object:nil]; |
| |
} |
| |
// Called when the UIKeyboardDidShowNotification is sent. |
- (void)keyboardWasShown:(NSNotification*)aNotification |
{ |
NSDictionary* info = [aNotification userInfo]; |
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; |
| |
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0); |
scrollView.contentInset = contentInsets; |
scrollView.scrollIndicatorInsets = contentInsets; |
| |
// If active text field is hidden by keyboard, scroll it so it's visible |
// Your application might not need or want this behavior. |
CGRect aRect = self.view.frame; |
aRect.size.height -= kbSize.height; |
if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) { |
CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y-kbSize.height); |
[scrollView setContentOffset:scrollPoint animated:YES]; |
} |
} |
| |
// Called when the UIKeyboardWillHideNotification is sent |
- (void)keyboardWillBeHidden:(NSNotification*)aNotification |
{ |
UIEdgeInsets contentInsets = UIEdgeInsetsZero; |
scrollView.contentInset = contentInsets; |
scrollView.scrollIndicatorInsets = contentInsets; |
} |
Additional methods for tracking the active text field.
- (void)textFieldDidBeginEditing:(UITextField *)textField |
{ |
activeField = textField; |
} |
| |
- (void)textFieldDidEndEditing:(UITextField *)textField |
{ |
activeField = nil; |
} |
There are other ways you can scroll the edited area in a scroll view above an obscuring keyboard. Instead of altering the bottom content inset of the scroll view, you can extend the height of the content view by the height of the keyboard and then scroll the edited text object into view. Although the UIScrollView class has a contentSize property that you can set for this purpose, you can also adjust the frame of the content view, as shown in Listing 4-3. This code also uses thesetContentOffset:animated: method to scroll the edited field into view, in this case scrolling it just above the top of the keyboard.
方法二:改变scrollview conentsize or frame,添加一个键盘的高度。
Listing 4-3 Adjusting the frame of the content view and scrolling a field above the keyboard
- (void)keyboardWasShown:(NSNotification*)aNotification { |
NSDictionary* info = [aNotification userInfo]; |
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; |
CGRect bkgndRect = activeField.superview.frame; |
bkgndRect.size.height += kbSize.height; |
[activeField.superview setFrame:bkgndRect]; |
[scrollView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height) animated:YES]; |
} |
UIKit Facilities for Copy-Paste Operations
-
The
UIPasteboardclass provides pasteboards: protected areas for sharing data within an application or between applications. The class offers methods for writing and reading items of data to and from a pasteboard. -
The
UIMenuControllerclass displays an edit menu above or below the selection to be copied, cut, or pasted into. The default commands of the edit menu are (potentially) Copy, Cut, Paste, Select, and Select All. You can also add custom menu items to the edit menu (see “Adding Custom Items to the Edit Menu”). -
The
UIResponderclass declares the methodcanPerformAction:withSender:. Responder classes can implement this method to show and remove commands of the edit menu based on the current context. -
The
UIResponderStandardEditActionsinformal protocol declares the interface for handling copy, cut, paste, select, and select-all commands. When users tap one of the commands in the edit menu, the correspondingUIResponderStandardEditActionsmethod is invoked.
UIPasteboard defines two system pasteboards, each with its own name and purpose:
-
UIPasteboardNameGeneralis for cut, copy, and paste operations involving a wide range of data types. You can obtain asingleton object representing the General pasteboard by invoking thegeneralPasteboardclass method. -
UIPasteboardNameFindis for search operations. The string currently typed by the user in the search bar (UISearchBar) is written to this pasteboard, and thus can be shared between applications. You can obtain an object representing the Find pasteboard by calling thepasteboardWithName:create:class method, passing inUIPasteboardNameFindfor the name.
Typically you use one of the system-defined pasteboards, but if necessary you can create your own application pasteboard using pasteboardWithName:create: If you invoke pasteboardWithUniqueName, UIPasteboard gives you a uniquely-named application pasteboard. You can discover the name of a pasteboard through its name property.
Pasteboard Persistence
Although application pasteboards by default are not persistent, an application can mark them as persistent by setting thepersistent
property to
YES
.
addItems: method of UIPasteboard to append items, the write methods of the class do not append items to the current contents of the pasteboard. In response to a copy: or cut: message, you write the object or data represented by the selection to the pasteboard in as many different representations as you can. This operation involves the following steps (which assume a single pasteboard item):
-
From the selection, identify or obtain the object or the binary data corresponding to the object.
Binary data must be encapsulated in an
NSDataobject. If you’re going to write another type of object to the pasteboard, it must be a property-list object—that is, an object of one of the following classes:NSString,NSArray,NSDictionary,NSDate,NSNumber, orNSURL. (For more on property-list objects, see Property List Programming Guide.) -
If possible, generate one or more other representations of the object or data.
For example, if in the previous step you created a
UIImageobject representing a selected image, you could use theUIImageJPEGRepresentationandUIImagePNGRepresentationfunctions to convert the image to a different representation. -
Obtain a pasteboard object.
In many cases, this is the general pasteboard, which you can get through the
generalPasteboardclass method. -
Assign a suitable UTI for each representation of data written to the pasteboard item.
See “Pasteboard Concepts” for a discussion of this subject.
-
Write the data to the first pasteboard item for each representation type:
-
To write a data object,send a
setData:forPasteboardType:message to the pasteboard object. -
To write a property-list object, send a
setValue:forPasteboardType:message to the pasteboard object.
-
-
If the command is Cut (
cut:method), remove the object represented by the selection from the application’s data modeland update your view.
Copying and cutting operations
- (void)copy:(id)sender { |
UIPasteboard *gpBoard = [UIPasteboard generalPasteboard]; |
ColorTile *theTile = [self colorTileForOrigin:currentSelection]; |
if (theTile) { |
NSData *tileData = [NSKeyedArchiver archivedDataWithRootObject:theTile]; |
if (tileData) |
[gpBoard setData:tileData forPasteboardType:ColorTileUTI]; |
} |
} |
| |
- (void)cut:(id)sender { |
[self copy:sender]; |
ColorTile *theTile = [self colorTileForOrigin:currentSelection]; |
| |
if (theTile) { |
CGPoint tilePoint = theTile.tileOrigin; |
[tiles removeObject:theTile]; |
CGRect tileRect = [self rectFromOrigin:tilePoint inset:TILE_INSET]; |
[self setNeedsDisplayInRect:tileRect]; |
} |
} |
Pasting the Selection
In response to a paste: message, you read an object from the pasteboard in a representation that your application supports. Then you add the pasted object to the application’s data model and display the new object in the view in the user-indicated location. This operation involves the following steps (which assume a single pasteboard item):
-
Obtain a pasteboard object.
In many cases, this is the general pasteboard, which you can get through the
generalPasteboardclass method. -
Verify that the first pasteboard item contains data in a representation that your application can handle by calling the
containsPasteboardTypes:method or thepasteboardTypesmethod and then examining the returned array of types.Note that you should have already performed this step in your implementation of
canPerformAction:withSender:. -
If the first item of the pasteboard contains data that the application can handle, call one of the following methods to read it:
-
dataForPasteboardType:if the data to be read is encapsulated in anNSDataobject. -
valueForPasteboardType:if the data to be read is encapsulated in a property-list object (see “Copying and Cutting the Selection”).
-
-
Add the object to the application’s data model.
-
Display a representation of the object in the user interface at the location specified by the user.
Pasting data to a selection
- (void)paste:(id)sender { |
UIPasteboard *gpBoard = [UIPasteboard generalPasteboard]; |
NSArray *pbType = [NSArray arrayWithObject:ColorTileUTI]; |
ColorTile *theTile = [self colorTileForOrigin:currentSelection]; |
if (theTile == nil && [gpBoard containsPasteboardTypes:pbType]) { |
NSData *tileData = [gpBoard dataForPasteboardType:ColorTileUTI]; |
ColorTile *theTile = (ColorTile *)[NSKeyedUnarchiver unarchiveObjectWithData:tileData]; |
if (theTile) { |
theTile.tileOrigin = self.currentSelection; |
[tiles addObject:theTile]; |
CGRect tileRect = [self rectFromOrigin:currentSelection inset:TILE_INSET]; |
[self setNeedsDisplayInRect:tileRect]; |
} |
} |
} |
Adding Custom Items to the Edit Menu
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { |
UITouch *theTouch = [touches anyObject]; |
if ([theTouch tapCount] == 2) { |
[self becomeFirstResponder]; |
UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:@"Change Color" action:@selector(changeColor:)]; |
UIMenuController *menuCont = [UIMenuController sharedMenuController]; |
[menuCont setTargetRect:self.frame inView:self.superview]; |
menuCont.arrowDirection = UIMenuControllerArrowLeft; |
menuCont.menuItems = [NSArray arrayWithObject:menuItem]; |
[menuCont setMenuVisible:YES animated:YES]; |
} |
} |
Creating an input accessory view programmatically
- (UIView *)inputAccessoryView { |
if (!inputAccessoryView) { |
CGRect accessFrame = CGRectMake(0.0, 0.0, 768.0, 77.0); |
inputAccessoryView = [[UIView alloc] initWithFrame:accessFrame]; |
inputAccessoryView.backgroundColor = [UIColor blueColor]; |
UIButton *compButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; |
compButton.frame = CGRectMake(313.0, 20.0, 158.0, 37.0); |
[compButton setTitle: @"Word Completions" forState:UIControlStateNormal]; |
[compButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; |
[compButton addTarget:self action:@selector(completeCurrentWord:) |
forControlEvents:UIControlEventTouchUpInside]; |
[inputAccessoryView addSubview:compButton]; |
} |
return inputAccessoryView; |
} |
@property (readonly, retain) UIView *inputView; |
@property (readonly, retain) UIView *inputAccessoryView; |
Adopting the UIInputViewAudioFeedback Protocol
Perform the following three steps to adopt the UIInputViewAudioFeedback protocol:
-
In your Xcode project, create a subclass of the
UIViewclass. In the header file, indicate that the subclass conforms to theUIInputViewAudioFeedbackprotocol, as follows:@interface KeyboardAccessoryView : UIView <UIInputViewAudioFeedback> {}
-
In the implementation file for your
UIViewsubclass, implement theenableInputClicksWhenVisiblemethod, as follows:- (BOOL) enableInputClicksWhenVisible {return YES;
}
-
Finally, in the Interface Builder document for your custom input or accessory view, select the View object. In the Identity inspector, set the class for the object to be your
UIViewsubclass.
Playing Input Clicks
To play an input click for a key tap in a custom input or keyboard accessory view, first ensure that view adopts theUIInputViewAudioFeedback protocol as described in “Adopting the UIInputViewAudioFeedback Protocol.” Then, for each tap that you want to provide a click sound for, call the playInputClick method of the UIDevice class, as follows:
- (void) playClickForCustomKeyTap { |
[[UIDevice currentDevice] playInputClick]; |
} |
本文介绍iOS中文本视图与键盘的交互过程,包括成为第一响应者前后发送的消息、编辑期间的方法调用、键盘显示时内容的调整策略等,并提供了自定义键盘和输入视图的具体实现。
1598

被折叠的 条评论
为什么被折叠?



