Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

HippoMan

macrumors newbie
Original poster
Jul 19, 2008
14
0
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):
Code:
#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;

@end

Here's my MyViewController.m:

#import "MyViewController.h"
Code:
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];
}

@end

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.
.​
 

HippoMan

macrumors newbie
Original poster
Jul 19, 2008
14
0
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.

AppDelegate.h:
Code:
#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;

@end

AppDelegate.m:
Code:
#import "AppDelegate.h"
#import "MyViewController.h"

static NSUInteger kNumberOfPages = 7;

@interface AppDelegate (PrivateMethods)

- (void)loadScrollViewWithPage:(int)page;
- (void)scrollViewDidScroll:(UIScrollView *)sender;

@end

@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
        return;
    }
    // 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;
}

@end
 

imrtt

macrumors newbie
Jul 19, 2008
23
0
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().
 

HippoMan

macrumors newbie
Original poster
Jul 19, 2008
14
0
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().
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?

Thanks.
.​
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.