Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animate Spinner when loading new page

I have a UITableView which from an external RSS feed.

When you select a row it uses navigationController and slides in from the right, the problem is that the RSS feed contains images therefore it can can take a few seconds to load and without any indication of what is going on you can mistake it for an application crash.

I decided to add a spinner so that you know that new page is loading.

Here is my code:

RootViewController.m

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"Loading New Page");

[tableView deselectRowAtIndexPath:indexPath animated:YES];
DetailsViewController *detailViewController = [[DetailsViewController alloc] initWithNibName:@"DetailsViewController" bundle:nil];
detailViewController.item = [rssItems objectAtIndex:floor(indexPath.row/2)];
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];

UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinner.center = CGPointMake(160, 240);
[self.view addSubview:spinner];
[spinner startAnimating];
[spinner release];

}

DetailsViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];

        NSString *imgURL = [item objectForKey:@"image"];
        NSData *mydata = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:imgURL]];
        item_photo.image = [[UIImage alloc] initWithData:mydata];

    item_title.text = [item objectForKey:@"title"];
    item_date.text = [NSString stringWithFormat:@"Date: %@",[item objectForKey:@"date"]];
    item_time.text = [NSString stringWithFormat:@"Time: %@",[item objectForKey:@"time"]];
    item_cost.text = [NSString stringWithFormat:@"Cost: £%@",[item objectForKey:@"cost"]];
    item_info.text = [item objectForKey:@"description"];
    self.navigationItem.title = @"Event Type";
}

There are two problems with this code.

  1. The Spinner does not active until after the new page has loaded.
  2. The Spinner does not disable once loaded.

If anyone could help me with this problem i would be truly gratefully.

like image 905
Eli Stone Avatar asked Jan 24 '12 16:01

Eli Stone


People also ask

How do you show page loading Div until the page has finished loading?

Step 1: Add a background with a spinner gif on top of the page, then remove them when everything is loaded. Step 2: Add a little script right after the opening body tag to start displaying the load/splash screen.


2 Answers

You are adding the activity indicator view to the view of the controller which is pushing the detail view controller, so you wont see it anyway

try moving the second group of code to the viewDidLoad method of DetailsViewController, you can call stopAnimating on the activity indicator when you are finished loading. To get a reference to the UIActivityIndicator you should add a tag

e.g. in viewDidLoad

UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinner.center = CGPointMake(160, 240);
spinner.tag = 12;
[self.view addSubview:spinner];
[spinner startAnimating];
[spinner release];

in the loadingFinished method (whichever method is called when finished loading)

[[self.view viewWithTag:12] stopAnimating];
like image 109
wattson12 Avatar answered Oct 29 '22 07:10

wattson12


You need to do some work in a background thread. If the following line is the one that takes the time:

detailViewController.item = [rssItems objectAtIndex:floor(indexPath.row/2)];

Then you could do this in the background with GCD:

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

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    // This is the operation that blocks the main thread, so we execute it in a background thread
    id item = [rssItems objectAtIndex:floor(indexPath.row/2)];

        // UIKit calls need to be made on the main thread, so re-dispatch there
        dispatch_async(dispatch_get_main_queue(), ^{
            detailViewController.item = item;
            [spinner stopAnimating];
        });
});

And +1 to @wattson12 - you need to add the spinner to the new view instead. Alternatively you could add the spinner to the current view, and instead put the pushViewControllercall into your GCD main-queue block.

Final point - you'll want to remove the spinner from its superview once you stop it animating. Alternatively, you can have a single instance of the spinner, and set hidesWhenStopped to YES.

like image 42
ikuramedia Avatar answered Oct 29 '22 07:10

ikuramedia