话说学 iOS , 想要提高,还是要看官方文档呐!感觉技术好久不进步了,貌似进入了技术瓶颈。着急下,尝试了不少渠道,读了些专业博客,发现知识点太碎了。订阅了raywenderlich 视频教程,发现它不够系统,或者就是每个知识点太入门太简单,看了一段时间感觉是在浪费时间,于是就转看 WWDC 了。现在每天早上坚持看一集或者更多。感觉非常不错。还是苹果自家出品的质量高啊,无论产品,还是技术,都应该给苹果点赞。这几天读了下 Text Programming Guide ,有不少收获,相见恨晚的感觉。接下来会系统读更多官方其它文档。
这里摘录一下阅读笔记。
一、Managing Text Fields and Text Views
1. Tracking Multiple Text Fields or Text Views
For the tag approach, declare a set of enum constants, one constant for each tag.
enum {
NameFieldTag = 0,
EmailFieldTag,
DOBFieldTag,
SSNFieldTag
};
Identifying the passed-in text object using tags:
- (void)textFieldDidEndEditing:(UITextField *)textField {
switch (textField.tag) {
case NameFieldTag:
// do something with this text field
break;
case EmailFieldTag:
// do something with this text field
break;
// remainder of switch statement....
}
}
the delegate should get the text and store it in the app’s data model. The best delegation methods for accessing entered text are textFieldDidEndEditing: and textViewDidEndEditing.
Getting the text entered into a text field:
- (void)textFieldDidEndEditing:(UITextField *)textField {
if ([textField.text isEqualToString:@""])
return;
switch (textField.tag) {
case NameFieldTag:
[thePerson setObject:textField.text forKey:MyAppPersonNameKey];
break;
case EmailFieldTag:
[thePerson setObject:textField.text forKey:MyAppPersonEmailKey];
break;
case SSNFieldTag:
[thePerson setObject:textField.text forKey:MyAppPersonSSNKey];
break;
default:
break;
}
}
2. Validating Entered Text
最佳校验时刻
The best delegation methods for validating entered strings are textFieldShouldEndEditing for text fields and textViewShouldEndEditing
for text views. These methods are called just before the text field or text view resigns first responder status.
e.g.
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
if (textField == SSN) { // SSN is an outlet
NSString *regEx = @"[0-9]{3}-[0-9]{2}-[0-9]{4}";
NSRange r = [textField.text rangeOfString:regEx options:NSRegularExpressionSearch];
if (r.location == NSNotFound) {
UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"Entry Error"
message:@"Enter social security number in 'NNN-NN-NNNN' format"
delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease];
[av show];
return NO;
}
}
return YES;
}
You can also implement the textField:shouldChangeCharactersInRange:replacementString:
method to offer possible word completions or corrections to the user as they enter text.
3. Tracking the Selection in Text Views
- (void)textViewDidChangeSelection:(UITextView *)textView {
NSRange r = textView.selectedRange;
if (r.length == 0) {
return;
}
NSString *selText = [textView.text substringWithRange:r];
NSString *upString = [selText uppercaseString];
NSString *newString = [textView.text stringByReplacingCharactersInRange:r withString:upString];
textView.text = newString;
}
二、 Managing the Keyboard
If the active text field is hidden by the keyboard, the keyboardWasShown: method adjusts the content offset of the scroll view appropriately. The active field is stored in a custom variable (called activeField in this example) that is a member variable of the view controller and set in the textFieldDidBeginEditing: delegate method, which is itself shown in Listing 4-2.
Listing 4-1 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 app might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
[self.scrollView scrollRectToVisible:activeField.frame animated:YES];
}
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
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 the setContentOffset:animated: method to scroll the edited field into view,in this case scrolling it just above the top of the keyboard.
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];
}
三、 Using Text Kit to Draw and Manage Text
Note: NLayoutManager, NSTextStorage, and NSTextContainer can be accessed from subthreads as long as the app guarantees the access from a single thread.
Text Attributes
Text Kit handles three kinds of text attributes: character attributes, paragraph attributes, and document attributes. Character attributes include traits such as font, color, and subscript, which can be associated with an individual character or a range of characters. Paragraph attributes are traits such as indentation, tabs, and line spacing. Document attributes include documentwide traits such as paper size, margins, and view zoom percentage.
Character Attributes
An attributed string stores character attributes as key-value pairs in NSDictionary objects. The key is an attribute name, represented by an identifier (an NSString constant) such as NSFontAttributeName.
Primary Text Kit Objects
NSTextContainer
An NSTextContainer object defines a region where text can be laid out. Typically, a text container defines a rectangular area, but by creating a subclass of NSTextContainer you can create other shapes: circles, pentagons, or irregular shapes, for example. Not only does a text container describe the outline of an area that can be filled with text, it maintains an array of Bezier paths that are exclusion zones within its area where text is not laid out. As it is laid out, text flows around the exclusion paths, providing a means to include graphics and other non-text layout elements.
NSTextStorage
NSTextStorage defines the fundamental storage mechanism of the Text Kit’s extended text-handling system. NSTextStorage is a subclass of NSMutableAttributedString that stores the characters and attributes manipulated by the text system. It ensures that text and attributes are maintained in a consistent state across editing operations. In addition to storing the text, an NSTextStorage object manages a set of client NSLayoutManager objects, notifying them of any changes to its characters or attributes so that they can relay and redisplay the text as needed.
NSLayoutManager
An NSLayoutManager object orchestrates the operation of the other text handling objects. It intercedes in operations that convert the data in an NSTextStorage object to rendered text in a view’s display area. It maps Unicode character codes to glyphs and oversees the layout of the glyphs within the areas defined by NSTextContainer objects.
Note: NLayoutManager, NSTextStorage, and NSTextContainer can be accessed from subthreads as long as the app guarantees the access from a single thread.
Text Attributes
Text Kit handles three kinds of text attributes: character attributes, paragraph attributes, and document attributes. Character attributes include traits such as font, color, and subscript, which can be associated with an individual character or a range of characters. Paragraph attributes are traits such as indentation, tabs, and line spacing. Document attributes include documentwide traits such as paper size, margins, and view zoom percentage.
Object creation for a single text flow
NSTextStorage* textStorage = [[NSTextStorage alloc] initWithString:string];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
self.textContainer = [[NSTextContainer alloc] initWithSize:self.view.bounds.size];
[layoutManager addTextContainer:self.textContainer];
UITextView* textView = [[UITextView alloc] initWithFrame:self.view.bounds textContainer:self.textContainer];
[self.view addSubview:textView];
This configuration is limited by having only one text container and one text view. In such an arrangement, the text flows uninterrupted within the area defined by the text container. Page breaks, multicolumn layout, and more complex layouts can’t be accommodated by this arrangement.
By using multiple text containers, each with an associated text view, more complex layout arrangements are possible. For example, to support page breaks, an app can configure the text objects as shown in Figure 8-7.
Each text container corresponds to a page of the document. The views displaying the text can be embedded in a custom view object that your app provides as a background for the text views. This custom view, in turn, can be embedded in a UIScrollView object to enable the user to scroll through the document’s pages.
Instead of having one text container correspond to a single page, there are now two text containers—one for each column on the page. Each text container controls a portion of the document. As the text is displayed, glyphs are first laid out in the top-left container. When there is no more room in that view, the layout manager informs its delegate that it has finished filling the container. The delegate can check to see whether there’s more text that needs to be laid out and add another text container if necessary. The layout manager proceeds to lay out text in the next container, notifies the delegate when finished, and so on. Again, a custom view (depicted as a blue rectangle) provides a canvas for these text columns.
Not only can you have multiple text containers, you can also have multiple NSLayoutManager objects accessing the same text storage. Figure 8-9 illustrates an object arrangement with multiple layout managers. The effect of this arrangement is to provide multiple views of the same text. If the user alters the text in the top view, the change is immediately reflected in the bottom view (assuming the location of the change is within the bottom view’s bounds).
Spell Checking and Word Completion
- (IBAction)spellCheckDocument:(id)sender {
NSInteger currentOffset = 0;
NSRange currentRange = NSMakeRange(0, 0);
NSString *theText = textView.text;
NSRange stringRange = NSMakeRange(0, theText.length-1);
NSArray *guesses;
BOOL done = NO;
NSString *theLanguage = [[UITextChecker availableLanguages] objectAtIndex:0];
if (!theLanguage)
theLanguage = @"en_US";
while (!done) {
currentRange = [textChecker rangeOfMisspelledWordInString:theText range:stringRange
startingAt:currentOffset wrap:NO language:theLanguage];
if (currentRange.location == NSNotFound) {
done = YES;
continue;
}
guesses = [textChecker guessesForWordRange:currentRange inString:theText
language:theLanguage];
NSLog(@"---------------------------------------------");
NSLog(@"Word misspelled is %@", [theText substringWithRange:currentRange]);
NSLog(@"Possible replacements are %@", guesses);
NSLog(@" ");
currentOffset = currentOffset + (currentRange.length-1);
}
}
The UITextChecker class includes methods for telling the text checker to ignore or learn words. Instead of just logging the misspelled words and their possible replacements, as the method in Listing 9-17 does, you should display some user interface that allows users to select correct spellings, tell the text checker to ignore or learn a word, and proceed to the next word without making any changes. One possible approach for an iPad app would be to use a popover view that lists the guesses in a table view and includes buttons such as Replace, Learn, Ignore, and so on.
You may also use UITextChecker to obtain completions for partially entered words and display the completions in a table view in a popover view. For this task, you call the completionsForPartialWordRange:inString:language: method, passing in the range in the given string to check. This method returns an array of possible words that complete the partially entered word. Listing 9-18 shows how you mig
参考: