0
votes

I need to load some data in a table view and while this is going on in the background I want to add an activity indicator in order to show that there is a process going on and will hide once the process finishes. What would be the most efficient way to implement something like this?

2

2 Answers

1
votes

Depends, whether you want to block your user or not and also how important is the activity indication.

If you don't want to block user, use Application.networkActivityIndicatorVisible, if you want to have larger activity indicator and still not to block user, animate UIView with text and UIActivityIndicator below the table view (tableview.height -= activityview.height) and then hide on complete or if you would like to block user, use blocking activity indicator.

0
votes

You can add a view which has a UIIndicatorView and a UILabel as your cell's subview. You can use this way to show error data loading/ error network/ empty data...

Example:

Your Controller can define two modes: UITableViewModeMessage and UITableViewModeData.

In viewDidLoad, you set self.tableViewMode = UITableViewModeMessage. When has returned data, set self.tableViewMode = UITableViewModeData and reload data for tableview.

Some code:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
    if (self.tableViewMode == UITableViewModeMessage) {
        return 2;
    } else {
        return self.yourEntries ? self.yourEntries.count : 0;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    if (self.tableViewMode == UITableViewModeMessage) {
        return [self tableView:tableView messageCellForRowAtIndexPath:indexPath];
    } else {
        return [self tableView:tableView dataCellForRowAtIndexPath:indexPath];
    }
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// Remove Loading... progress view if exist.
    UIView *progressView = [cell viewWithTag:100];
    [progressView removeFromSuperview];

    if (self.tableViewMode == UITableViewModeMessage) {        
        if (indexPath.row == 1) {
            // remove the current label.
            cell.textLabel.text = nil;

            // We build progress view and attach to cell here but not in cellForRowAtIndexPath is because in this method cell frame is already calculated.
            UIView *progressView = [self progressViewForCell:cell message:@"Loading..." alpha:0.9];
            [cell addSubview:progressView];
        }
    }
}


// cell to display when loading
- (UITableViewCell *)tableView:(UITableView *)tableView messageCellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"MessageCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        cell.textLabel.textColor = [UIColor grayColor];
        cell.textLabel.textAlignment = UITextAlignmentCenter;
    }

    if (indexPath.row == 1) {
        cell.textLabel.text = @"Loading...";
    } else {
        cell.textLabel.text = nil;
    }

    return cell;
}

// cell to display when has data
- (UITableViewCell *)tableView:(UITableView *)tableView dataCellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    static NSString *CellIdentifier = @"DataCell";

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    cell.textLabel.text = [[self.yourEntries objectAtIndex:indexPath.row] description];

    return cell;
}

// Build a view which has a UIActivityIndicatorView and a UILabel
- (UIView *)progressViewForCell:(UITableViewCell *)cell message:(NSString *)message alpha:(CGFloat)alpha
{
    // NOTE: progressView needs to be removed from cell in cellForRowAtIndexPath:
    CGRect progressViewFrame = CGRectZero;
    progressViewFrame.size.width = CGRectGetMaxX(cell.bounds);
    progressViewFrame.size.height = CGRectGetMaxY(cell.bounds) - 2;

    UIView *progressView = [[UIView alloc] initWithFrame:progressViewFrame];
    progressView.backgroundColor = RGBA(255, 255, 255, 1);
    progressView.alpha = alpha;
    progressView.tag = 100;

    UILabel *loadingLabel = [[UILabel alloc] initWithFrame:progressView.bounds];
    loadingLabel.backgroundColor = [UIColor clearColor];
    loadingLabel.font = [UIFont systemFontOfSize:14];
    loadingLabel.textColor = [UIColor blackColor];
    loadingLabel.textAlignment = UITextAlignmentCenter;
    loadingLabel.text = message;

    CGFloat widthOfText = [loadingLabel.text sizeWithFont:loadingLabel.font].width;
    CGFloat spaceBetweenIndicatorAndLabel = 5;

    // activityIndicatorView has size in which width and height is equal to 20.
    UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    [activityIndicatorView setCenter:CGPointMake(CGRectGetMidX(cell.bounds) - (widthOfText / 2) - (activityIndicatorView.bounds.size.width / 2) - spaceBetweenIndicatorAndLabel, CGRectGetMidY(cell.bounds))]; 
    [activityIndicatorView setColor:[UIColor blackColor]];
    [activityIndicatorView startAnimating];

    [progressView addSubview:activityIndicatorView];
    [progressView addSubview:loadingLabel];

    return progressView;
}