开发者

UITableView with Custom Cell only loads one row of data at a time

I want to build a train arrival time reference app, that lets me choose different stations and displays times from A to B, and times from B to A. So I'm using Apple's Page Control because I want to have multiple pages for each station, and each page would list all the train times. Here's my appdelegate:

#import "AppDelegate.h"
#import "MyViewController.h"

static NSUInteger kNumberOfPages = 2;

@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]) {
                contro开发者_JS百科ller = [[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 begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
        pageControlUsed = NO;
}

// 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

The app delegate loads up "MyViewController". What I'm trying to do with my view controller, is have two separate normal tables with different sets of information. I was able to achieve this.

I then modified the two tables to have custom cells consisting of two labels that I want to be able to set. Here is MyViewControler:

#import "MyViewController.h"
#import "CustomCell.h"

static NSArray *__pageControlColorList = nil;
static NSArray *__stationNameList = nil;

@implementation MyViewController

@synthesize stationName;
@synthesize homeBound;
@synthesize workBound;
@synthesize homeBoundTimes;
@synthesize workBoundTimes;
@synthesize Custom;

// 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 colorWithRed:16.0/255 green:102.0/255 blue:73.0/255 alpha:1.0], 
                                                                  [UIColor colorWithRed:248.0/255 green:155.0/255 blue:70.0/255 alpha:1.0], nil];
    }

    // Mod the index by the list length to ensure access remains in bounds.
    return [__pageControlColorList objectAtIndex:index % [__pageControlColorList count]];
}

//Creates the station list the first time this method is invoked. Returns one string object from the list.
+ (NSString *)pageControlStationWithIndex:(NSUInteger)index {
    if (__stationNameList == nil) {
        __stationNameList = [[NSArray alloc] initWithObjects:[NSString stringWithFormat:@"Bramalea"], [NSString stringWithFormat:@"Erindale"], nil];
    }   

    //Mod the index by the list length to ensure access remains in bounds.
    return [__stationNameList objectAtIndex:index % [__stationNameList count]];
}

//Creates the station list the first time this method is invoked. Returns one string object from the list.

+ (NSArray *)HomeTimesByIndex:(NSUInteger)index {
    if (index == 0) {       
        return [[NSArray alloc] initWithObjects:@"5:55 am", @"6:49 am", @"7:14 am", @"7:30 am", @"7:38 am", 
                                                @"8:07 am", @"9:20 am", @"10:25 am", @"11:06 am", @"12:15 pm", 
                                                @"1:45 pm", @"2:51 pm", @"3:51 pm", @"4:51 pm", @"5:51 pm", 
                                                @"6:51 pm", @"7:21 pm", @"7:51 pm", @"8:51 pm", @"9:51 pm", nil];
    } else {

        return [[NSArray alloc] initWithObjects:@"5:10 am", @"5:45 am", @"6:45 am", @"7:10 am",  
                                                @"7:30 am", @"7:45 am", @"8:00 am", @"8:15 am", 
                                                @"8:30 am", @"9:05 am", @"9:40 am", @"10:15 am",
                                                @"10:45 am", @"11:15 am", @"11:45 am", @"12:15 pm",
                                                @"12:45 pm", @"1:15 pm", @"1:45 pm", @"2:15 pm", @"2:45 pm", 
                                                @"3:15 pm", @"3:45 pm", @"4:15 pm", @"5:20 pm", @"6:20 pm", 
                                                @"7:15 pm", @"8:15 pm", @"9:15 pm", @"10:15 pm", @"11:15 pm", nil];
    }
}

+ (NSArray *)WorkTimesByIndex:(NSUInteger)index {
    if (index == 0) {       
        return [[NSArray alloc] initWithObjects:@"6:25 am", @"7:30 am", @"8:30 am", @"9:40 am", @"11:30 am", @"1:00 pm", @"1:50 pm", 
                                                @"2:00 pm", @"2:45 pm", @"4:15 pm", @"4:45 pm", @"5:15 pm", @"5:45 pm", @"6:45 pm", 
                                                @"7:20 pm", @"7:35 pm", @"7:55 pm", @"8:15 pm", @"8:35 pm", @"9:00 pm", @"9:30 pm", 
                                                @"10:00 pm", @"10:30 pm", @"11:00 pm", @"11:30 pm", @"12:01 am", @"12:30 am", @"1:30 am", nil];
    } else {
        return [[NSArray alloc] initWithObjects:
        @"6:20 am", @"7:20 am", @"8:20 am", @"9:20 am", @"10:20 am", @"11:20 am", @"12:20 pm", 
                @"12:50 pm", @"1:20 pm", @"1:40 pm", @"2:00 pm", @"2:20 pm", @"2:40 pm", @"2:55 pm",
        @"3:10 pm", @"3:25 pm", @"4:30 pm", @"4:50 pm", @"5:10 pm", @"5:25 pm", @"5:40 pm", 
        @"6:10 pm", @"7:00 pm", @"7:25 pm", @"7:40 pm", @"7:55 pm", @"8:10 pm", @"8:30 pm", 
        @"8:50 pm", @"9:10 pm", @"9:30 pm", @"9:50 pm", @"10:20 pm", @"11:20 pm", @"12:20 am", @"1:20 am", nil];
    }
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    CGRect frame = self.view.frame;
    frame.size.height = 600;
    self.view.frame = frame;
}


// Load the view nib and initialize the pageNumber ivar.
- (id)initWithPageNumber:(int)page {
    if (self = [super initWithNibName:@"Station" bundle:nil]) {
        pageNumber = page;
    }
    return self;
}

- (void)dealloc {
    [stationName release];
    [homeBound release];
    [workBound release];

    [homeBoundTimes release];
    [workBoundTimes release];

    [Custom release];

    [super dealloc];
}


// Set the label and background color when the view has finished loading.
- (void)viewDidLoad {
    //Get station name and set station texts
    stationName.text = [MyViewController pageControlStationWithIndex:pageNumber];
    homeBound.text = [NSString stringWithFormat:@"Next Train From Union to %@:", [MyViewController pageControlStationWithIndex:pageNumber]];
    workBound.text = [NSString stringWithFormat:@"Next Train From %@ to Union:", [MyViewController pageControlStationWithIndex:pageNumber]];
    self.view.backgroundColor = [MyViewController pageControlColorWithIndex:pageNumber];

    NSArray *arrayHome = [MyViewController HomeTimesByIndex:pageNumber];
    NSArray *arrayWork = [MyViewController WorkTimesByIndex:pageNumber];

    self.homeBoundTimes = arrayHome;
    self.workBoundTimes = arrayWork;

    [arrayHome release];
    [arrayWork release];

}

#pragma mark -
#pragma mark Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView 
    numberOfRowsInSection:(NSInteger)section {

    if ([tableView tag] == 0) {
        return [self.homeBoundTimes count];
    } else if ([tableView tag] == 1) {
        return [self.workBoundTimes count];
    }

    return 0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CustomCellIdentifier = @"CustomCellIdentifier";

    CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];

    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
        cell = self.Custom;
    }

    NSUInteger row = [indexPath row];

    if ([tableView tag] == 0) {
        cell.arriveTimeLabel.text = [homeBoundTimes objectAtIndex:row]; 
        cell.departTimeLabel.text = [homeBoundTimes objectAtIndex:row]; 
    } else if ([tableView tag] == 1) {
        cell.arriveTimeLabel.text = [workBoundTimes objectAtIndex:row]; 
        cell.departTimeLabel.text = [workBoundTimes objectAtIndex:row];         
    }


    return cell;

}


@end

The values to be loaded into the table are hardcoded for now (experimenting with the db next).

My problem, is that when the table is viewed, only the first row has data, and the rest of the data "sorta" loads when I start scrolling down. By "sorta", only the first row will load at a time. The only time I get to see all the data, is when I scroll to the bottom, then scroll up again or when I select a row. But the information doesn't stay at all times. Sometimes when I scroll, I will lose the information until I scroll over that particular row again.

Does anyone have any ideas why this is happening?

Edit: Jim's answer did the trick. Here's my modified method:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCellIdentifier"];
    if (cell == nil) {
        // Load the top-level objects from the custom cell XIB.
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
        // Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
        cell = [topLevelObjects objectAtIndex:0];

        NSUInteger row = [indexPath row];

        if ([tableView tag] == 0) {
            cell.arriveTimeLabel.text = [homeBoundTimes objectAtIndex:row];
            cell.departTimeLabel.text = [homeBoundTimes objectAtIndex:row];
        } else if ([tableView tag] == 1) {
            cell.arriveTimeLabel.text = [workBoundTimes objectAtIndex:row]; 
            cell.departTimeLabel.text = [workBoundTimes objectAtIndex:row];         
        }   

    }

    return cell;
}


In every case I've seen where table view cells change their contents due to scrolling, it has been caused by a problem with the reuse identifier.

Inspect your UITableViewCell in Interface Builder. Look at the "Identifier" field. Make sure it matches the string you're passing to dequeueReusableCellWithIdentifier: ("CustomCellIdentifier").

Also, if you have another table in your app with cells that are configured differently, make sure you're using a different reuse identifier for those cells.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜