简体   繁体   中英

How to add a custom cell to the bottom of a UITableView?

I've a UITableView where the data source is Core Data using a NSFetchRequest . The Core Data contains news items downloaded from the database on my website. The Core Data is by default containing the 50 newest items and older items is lazy downloaded, when the bottom of the UITableView is reached.

I'm currently dealing with this using the tableView:numberOfRowsInSection method, where I'm returning +1 for the last section, which is my "Loading items" cell. In the tableView:cellForRowAtIndexPath method I'm creating the "Loading items" cell, when the IndexPath is the last row in the last section.

By problem is, that when the new data is downloaded the cell that before was the "Loading items" cell, is now a regular news item cell. But then cell is first reloaded, when I scroll away from the cell and comes back.

I could store the indexPath for the "loading items" cell and reload that cell, when the lazy load is finished. But I would like to know, if any better solutions to this problem exists?

EDIT1:

Here is my procedure for creating the "loading items" UITableViewCell.

cell.textLabel.text = [NSString stringWithFormat:@"%@\u2026", NSLocalizedString(@"LOADING_MORE", nil)];

UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];

UIImage *spacer = [UIImage imageNamed:@"Spacer"];

UIGraphicsBeginImageContext(spinner.frame.size);
[spacer drawInRect:CGRectMake(0,0,spinner.frame.size.width,spinner.frame.size.height)];
UIImage* resizedSpacer = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

cell.imageView.image = resizedSpacer;
[cell.imageView addSubview:spinner];
[spinner startAnimating];

EDIT2:

I'm trying to "design" the footerView using the below code. Currently the activity indicator is places in the top left position and the label is not visible.

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
    NSInteger sectionsAmount = [tableView numberOfSections];
    if (section == sectionsAmount - 1) {
        return 20;
    }
    return 0;
}

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
    NSInteger sectionsAmount = [tableView numberOfSections];
    if (section == sectionsAmount - 1) {
        if (_tableFooterView==nil) {
            UIView *view = [[UIView alloc] init];

            UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];

            UIImage *spacer = [UIImage imageNamed:@"Spacer"];

            UIGraphicsBeginImageContext(spinner.frame.size);
            [spacer drawInRect:CGRectMake(0,0,spinner.frame.size.width,spinner.frame.size.height)];
            UIImage* resizedSpacer = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();

            UIImageView *imageView = [[UIImageView alloc] init];

            imageView.image = resizedSpacer;
            [imageView addSubview:spinner];
            [spinner startAnimating];

            [view addSubview:imageView];

            UILabel *label = [[UILabel alloc] init];
            label.text = [NSString stringWithFormat:@"%@\u2026", NSLocalizedString(@"LOADING_MORE", nil)];
            [view addSubview:label];

            _tableFooterView = view;
        }
        return self.tableFooterView;
    }
    return nil;
}

How can I change the UIView to look like the the below image: 正在加载更多..

EDIT3:

Here is my setupTableFooterView where I'm assigning a view to the tableFooterView . The method is called from the viewDidLoad .

- (void) setupTableFooterView {
    UIView *view = [[UIView alloc] init];

    UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];

    UIImage *spacer = [UIImage imageNamed:@"Spacer"];

    UIGraphicsBeginImageContext(spinner.frame.size);
    [spacer drawInRect:CGRectMake(0,0,spinner.frame.size.width,spinner.frame.size.height)];
    UIImage* resizedSpacer = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIImageView *imageView = [[UIImageView alloc] init];

    imageView.image = resizedSpacer;
    [imageView addSubview:spinner];
    [spinner startAnimating];

    imageView.frame = CGRectMake(10, 11, 20, 20);
    [view addSubview:imageView];

    UILabel *label = [[UILabel alloc] init];
    label.text = [NSString stringWithFormat:@"%@\u2026", NSLocalizedString(@"LOADING_MORE", nil)];
    [label setFont:[UIFont italicSystemFontOfSize:13]];
    [label setFrame:CGRectMake(40, 0, 270, 43)];
    [view addSubview:label];

    self.tableView.tableFooterView = view;
}

Use the UITableView tableFooterView instead for that message. That way you do not have to fiddle around with the section/row-structures.

From the UITableView reference :

tableFooterView

Returns an accessory view that is displayed below the table.

@property(nonatomic, retain) UIView *tableFooterView

Discussion

The default value is nil. The table footer view is different from a section footer.

are you not using [tableView reloadData] in your lazy download callback? So when the server sends back more results, and they're added to your data source, the table drawing logic gets reinvoked and the additions to numberOfRowsInSection are properly accounted for?

Additionally, I think your suggestion on just assigning the last cell of the table as a "Loading Cell" would probably work fine. Synthesize a retained property or member variable and store your LoadingCell reference in it, and just check the indexPath before all of the cell creation logic is invoked. If it's the last cell in the table, just return self.loadingCell.

I assume you currently have just one section in your table view. Make two sections instead. The first section contains just the normal data rows. The second section contains just the "Loading items" cell.

When new data is available, inform the table view of the new rows using insertRowsAtIndexPaths:withRowAnimation: .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM