UITextView not (re-)displaying text

Discussion in 'iPhone/iPad Programming' started by HippoMan, Jul 19, 2008.

  1. macrumors newbie

    I'm a new iPhone developer, and as a learning exercise, I decided to modify the PageControl sample application from the iPhone development site. I want to add a scrolling list of text to each of the seven pages that are displayed within this app.

    Using the Interface Builder, I added a UITextView object within the UIView object at the same level as the already existing UILabel object. I then managed this UITextView within the code in a similar way to how the UILabel was being managed (see below for my code).

    However, the UITextView only displays text on the first page, and it's empty (or missing?) on all of the other pages. The UILabel displays its text fine on all pages.

    I'm sure that I must be doing something wrong, but I can't figure out what.

    Here's my code. First, the code from MyViewController.h (the code that I added to the standard sample app is in bold):
    #import <UIKit/UIKit.h>
    @interface MyViewController : UIViewController {
        IBOutlet UILabel *pageNumberLabel;
    [B]    IBOutlet UITextView *pageText;[/B]
        int pageNumber;
    @property (nonatomic, retain) UILabel *pageNumberLabel;
    [B]@property (nonatomic, retain) UITextView *pageText;[/B]
    - (id)initWithPageNumber:(int)page;
    Here's my MyViewController.m:

    #import "MyViewController.h"
    static NSArray *__pageControlColorList = nil;
    @implementation MyViewController
    @synthesize pageNumberLabel;
    [B]@synthesize pageText;[/B]
    // Creates the color list the first time this method is invoked. Returns one color object from the list.
    + (UIColor *)pageControlColorWithIndex:(NSUInteger)index {
        if (__pageControlColorList == nil) {
            __pageControlColorList = [[NSArray alloc] initWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor magentaColor],
                                      [UIColor blueColor], [UIColor orangeColor], [UIColor brownColor], [UIColor grayColor], nil];
        // Mod the index by the list length to ensure access remains in bounds.
        return [__pageControlColorList objectAtIndex:index % [__pageControlColorList count]];
    // Load the view nib and initialize the pageNumber ivar.
    - (id)initWithPageNumber:(int)page {
        if (self = [super initWithNibName:@"MyView" bundle:nil]) {
            pageNumber = page;
        return self;
    - (void)dealloc {
        [pageNumberLabel release];
    [B]    [pageText release];[/B]
        [super dealloc];
    // Set the label and background color when the view has finished loading.
    - (void)viewDidLoad {
        pageNumberLabel.text = [NSString stringWithFormat:@"Page %d", pageNumber + 1];
    [B]    pageText.text = [NSString stringWithFormat:@"Text page %d", pageNumber + 1];[/B]
        self.view.backgroundColor = [MyViewController pageControlColorWithIndex:pageNumber];
    The other source files from this standard sample app are unchanged.

    By the way, I connected the outlets for the UITextView object using the Interface Builder in the same way that they were connected for the already existing UILabel (I think!).

    So what am I missing? Why is the text in the UITextView only showing up on the first of the seven pages in this app, even though the text in the UILabel shows up on all of these pages?

    Thanks in advance.
  2. macrumors newbie

    PS: in case this might be helpful, here are the other two important source files of this sample app, even though I didn't make any changes to them.

    #import <UIKit/UIKit.h>
    @interface AppDelegate : NSObject <UIApplicationDelegate, UIScrollViewDelegate> {
        IBOutlet UIWindow *window;
        IBOutlet UIScrollView *scrollView;
        IBOutlet UIPageControl *pageControl;
        NSMutableArray *viewControllers;
        // To be used when scrolls originate from the UIPageControl
        BOOL pageControlUsed;
    @property (nonatomic, retain) UIWindow *window;
    @property (nonatomic, retain) UIScrollView *scrollView;
    @property (nonatomic, retain) UIPageControl *pageControl;
    @property (nonatomic, retain) NSMutableArray *viewControllers;
    - (IBAction)changePage:(id)sender;
    #import "AppDelegate.h"
    #import "MyViewController.h"
    static NSUInteger kNumberOfPages = 7;
    @interface AppDelegate (PrivateMethods)
    - (void)loadScrollViewWithPage:(int)page;
    - (void)scrollViewDidScroll:(UIScrollView *)sender;
    @implementation AppDelegate
    @synthesize window, scrollView, pageControl, viewControllers;
    - (void)dealloc {
        [viewControllers release];
        [scrollView release];
        [pageControl release];
        [window release];
        [super dealloc];
    - (void)applicationDidFinishLaunching:(UIApplication *)application {
        // view controllers are created lazily
        // in the meantime, load the array with placeholders which will be replaced on demand
        NSMutableArray *controllers = [[NSMutableArray alloc] init];
        for (unsigned i = 0; i < kNumberOfPages; i++) {
            [controllers addObject:[NSNull null]];
        self.viewControllers = controllers;
        [controllers release];
        // a page is the width of the scroll view
        scrollView.pagingEnabled = YES;
        scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
        scrollView.showsHorizontalScrollIndicator = NO;
        scrollView.showsVerticalScrollIndicator = NO;
        scrollView.scrollsToTop = NO;
        scrollView.delegate = self;
        pageControl.numberOfPages = kNumberOfPages;
        pageControl.currentPage = 0;
        // pages are created on demand
        // load the visible page
        // load the page on either side to avoid flashes when the user starts scrolling
        [self loadScrollViewWithPage:0];
        [self loadScrollViewWithPage:1];
    - (void)loadScrollViewWithPage:(int)page {
        if (page < 0) return;
        if (page >= kNumberOfPages) return;
        // replace the placeholder if necessary
        MyViewController *controller = [viewControllers objectAtIndex:page];
        if ((NSNull *)controller == [NSNull null]) {
            controller = [[MyViewController alloc] initWithPageNumber:page];
            [viewControllers replaceObjectAtIndex:page withObject:controller];
            [controller release];
        // add the controller's view to the scroll view
        if (nil == controller.view.superview) {
            CGRect frame = scrollView.frame;
            frame.origin.x = frame.size.width * page;
            frame.origin.y = 0;
            controller.view.frame = frame;
            [scrollView addSubview:controller.view];
    - (void)scrollViewDidScroll:(UIScrollView *)sender {
        // We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
        // which a scroll event generated from the user hitting the page control triggers updates from
        // the delegate method. We use a boolean to disable the delegate logic when the page control is used.
        if (pageControlUsed) {
            // do nothing - the scroll was initiated from the page control, not the user dragging
        // Switch the indicator when more than 50% of the previous/next page is visible
        CGFloat pageWidth = scrollView.frame.size.width;
        int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
        pageControl.currentPage = page;
        // load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
        [self loadScrollViewWithPage:page - 1];
        [self loadScrollViewWithPage:page];
        [self loadScrollViewWithPage:page + 1];
        // A possible optimization would be to unload the views+controllers which are no longer visible
    // At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
        pageControlUsed = NO;
    - (IBAction)changePage:(id)sender {
        int page = pageControl.currentPage;
        // load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
        [self loadScrollViewWithPage:page - 1];
        [self loadScrollViewWithPage:page];
        [self loadScrollViewWithPage:page + 1];
        // update the scroll view to the appropriate page
        CGRect frame = scrollView.frame;
        frame.origin.x = frame.size.width * page;
        frame.origin.y = 0;
        [scrollView scrollRectToVisible:frame animated:YES];
        // Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above.
        pageControlUsed = YES;
  3. macrumors newbie

    For UITextView to be updated, it needs to be visible. I ran into the same problem with my app. Just add the updates to viewDidLoad().
  4. macrumors newbie

    Thanks for your reply.

    I'm confused, however. If you look in my topmost posting in this thread, you'll see that I'm indeed setting the text of the UITextView objects in viewDidLoad (it's the line I highlighted in bold within the listing of that method). When you say "add the updates", are you referring to something other than setting the text?


Share This Page