Making the Most of UITextView in iOS 7: NSTextStorage, NSLayoutManager, NSTextContainer and NSAttributedString

Most likely if you're using UITextView then you'll want to take advantage of attributed (or styled) strings. So let's create a NSAttributedString first of all:

NSAttributedString *textString =  [[NSAttributedString alloc] initWithString:@"Hello World" attributes:@{NSFontAttributeName: [UIFont fontWithName:@"HoeflerText-Italic" size:12]}];

Now, it might seem convenient to create a UITextView and add the attributed string like this:

UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 20, self.view.bounds.size.width, self.view.bounds.size.height)];
 
textView.attributedText=textString;

[self.view addSubview:textView];

But that would be the wrong thing to do if we want to take maximum advantage of all the classes, methods and delegates available to us when using UITextView. So what should be done first is to add the attributed string into a NSTextStorage object:

NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:textString];

Then we need to create an NSLayoutManager object:

NSLayoutManager *textLayout = [[NSLayoutManager alloc] init];

Next we have to add the layout manager to the text storage object:

[textStorage addLayoutManager:textLayout];

The step after this is to create an NSTextContainer object:

NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:self.view.bounds.size];

Before adding the container to the layout manager:

[textLayout addTextContainer:textContainer];

And finally, we create the text view using the text container we created:

UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20,20,self.view.bounds.size.width-20,self.view.bounds.size.height-20)
                                      textContainer:textContainer];

And this is added the view, so that our complete code looks like this:

NSAttributedString *textString =  [[NSAttributedString alloc] initWithString:@"Hello World" attributes:@{
                                                                                                            NSFontAttributeName: [UIFont fontWithName:@"HoeflerText-Italic" size:12]
                                                                                                            }];
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:textString];
NSLayoutManager *textLayout = [[NSLayoutManager alloc] init];
// Add layout manager to text storage object
[textStorage addLayoutManager:textLayout];
// Create a text container
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:self.view.bounds.size];
// Add text container to text layout manager
[textLayout addTextContainer:textContainer];
// Instantiate UITextView object using the text container
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20,20,self.view.bounds.size.width-20,self.view.bounds.size.height-20)
                                      textContainer:textContainer];
// Add text view to the main view of the view controler

[self.view addSubview:textView];


If this code is cut and pasted into the viewDidLoad method of a view controller it should work perfectly. The next thing to do is to examine all of the above classes and to explore what now becomes possible.

I've also added a post on paging and paginating using UITextView in combination with UIScrollView.

Endorse  on Coderwall

Comments