Paging and paginating the easy way with UITextView and UIScrollView in iOS 7 (Xcode)

Following yesterday's post on the right way to use UITextView, I wanted to put it together with the contents of an earlier post on UIScrollView in order to show how simple it is to let iOS 7 work out the pagination for you.

I'm not going to hold your hand in this post, instead I'll ask you to refer back to the two earlier posts if there's something that isn't clear in the following code and its comments:

// Create a scroll view
UIScrollView *scrollingView = [[UIScrollView alloc] initWithFrame:CGRectMake(20,20,self.view.bounds.size.width-20,self.view.bounds.size.height-20)];
// Make the scroll view content size big enough for four pages
scrollingView.contentSize  = CGSizeMake((self.view.bounds.size.width-20)*4,self.view.bounds.size.height-20);
// Enable paging in scroll view
scrollingView.pagingEnabled = YES;
// Add scroll view to view
[self.view addSubview:scrollingView];
   
// Create string - content
NSAttributedString *textString =  [[NSAttributedString alloc] initWithString:@"‘NOW, what I want is, Facts.  Teach these boys and girls nothing but Facts.  Facts alone are wanted in life.  Plant nothing else, and root out everything else.  You can only form the minds of reasoning animals upon Facts: nothing else will ever be of any service to them.  This is the principle on which I bring up my own children, and this is the principle on which I bring up these children.  Stick to Facts, sir!’ The scene was a plain, bare, monotonous vault of a school-room, and the speaker’s square forefinger emphasized his observations by underscoring every sentence with a line on the schoolmaster’s sleeve.  The emphasis was helped by the speaker’s square wall of a forehead, which had his eyebrows for its base, while his eyes found commodious cellarage in two dark caves, overshadowed by the wall.  The emphasis was helped by the speaker’s mouth, which was wide, thin, and hard set.  The emphasis was helped by the speaker’s voice, which was inflexible, dry, and dictatorial.  The emphasis was helped by the speaker’s hair, which bristled on the skirts of his bald head, a plantation of firs to keep the wind from its shining surface, all covered with knobs, like the crust of a plum pie, as if the head had scarcely warehouse-room for the hard facts stored inside.  The speaker’s obstinate carriage, square coat, square legs, square shoulders,—nay, his very neckcloth, trained to take him by the throat with an unaccommodating grasp, like a stubborn fact, as it was,—all helped the emphasis. ‘In this life, we want nothing but Facts, sir; nothing but Facts!’ The speaker, and the schoolmaster, and the third grown person present, all backed a little, and swept with their eyes the inclined plane of little vessels then and there arranged in order, ready to have imperial gallons of facts poured into them until they were full to the brim." attributes:@{NSFontAttributeName: [UIFont fontWithName:@"HoeflerText-Italic" size:25]                                                                                                                                 }];
// Set up text storage and add string
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:textString];
// Create a layout manager
NSLayoutManager *textLayout = [[NSLayoutManager alloc] init];
// Add layout manager to text storage object
[textStorage addLayoutManager:textLayout];
   
// create text containers and views, adding each container to the layout manager
int i=0;

while (i<=4) {
// Create a text container
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:scrollingView.frame.size];
// Add text container to text layout manager
[textLayout addTextContainer:textContainer];
// Instantiate UITextView object using the text container
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(scrollingView.frame.size.width*i,0,scrollingView.frame.size.width,scrollingView.frame.size.height) textContainer:textContainer];
// Give the container an identifier tag
[textView setTag:i];

// Add text view to the scroll view
[scrollingView addSubview:textView];
   i++;
        }

I'd recommend placing this code inside the viewDidLoad of your view controller and then running in an iOS simulator for an iPhone (or on the real thing if you prefer). As you will see the NSLayoutManager object in combination with NSTextStorage and NSTextContainer handle the pagination so that none of the text overflows or gets cut off.

What I've not yet done here is to make the number of pages dynamic, instead I've decided there are going to be four pages and I know the content at the font size specified will fit. In order to add the dynamic element, you need to take advantage of the NSLayoutManager delegate methods.

The next step to advancing your understanding of text and Text Kit in iOS 7 is to read Chapter 10 of Matt Neuburg's Programming iOS 7.

Endorse on Coderwall

Comments

  1. Will crash if got too many pages, I have no idea to solve this problem.
    ��

    ReplyDelete
  2. Hi,

    Thanks for this article. It helps me a lot in understanding NSTextContainer. I was so puzzled on how to find the amount of text that can be accommodated in a given screen size. But through this article I get to learn about NSTextContainer and its role.

    I have also used didCompleteLayoutForTextContainer to add dynamic pages to scroll view.

    It seems like the code does not work properly on Iphone6/IOS 9.1. It did work great on Iphone 4/IOS 7 but seems like it has issue with 9.1.

    The issue seems to be with UIScrollView's width but if you have faced similar issue and have the solution then please do let me know.

    Thanks

    ReplyDelete
    Replies
    1. Thank you for drawing my attention to this. It's been a while since I wrote this post but will endeavour to re-explore.

      Delete
  3. Hello there, I am struggling with dynamic paging. Can anyone help me, please?

    ReplyDelete

Post a Comment