i want display an activity indicator over a uitableview while it\'s loading data (in another thread). So in the ViewDidLoad method of the UITableViewController:
[iOS 5 +]
If you just want to show the activityWheel without an additional parentview, you can also add the activityWheel straight to the tableView and calculate the y value for the frame using the tableViews contentOffset:
@interface MyTableViewController ()
@property (nonatomic, strong) UIActivityIndicatorView *activityView;
@end
// ....
- (void) showActivityView {
if (self.activityView==nil) {
self.activityView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectZero];
[self.tableView addSubview:self.activityView];
self.activityView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
self.activityView.hidesWhenStopped = YES;
// additional setup...
// self.activityView.color = [UIColor redColor];
}
// Center
CGFloat x = UIScreen.mainScreen.applicationFrame.size.width/2;
CGFloat y = UIScreen.mainScreen.applicationFrame.size.height/2;
// Offset. If tableView has been scrolled
CGFloat yOffset = self.tableView.contentOffset.y;
self.activityView.frame = CGRectMake(x, y + yOffset, 0, 0);
self.activityView.hidden = NO;
[self.activityView startAnimating];
}
- (void) hideActivityView {
[self.activityView stopAnimating];
}
If the activityView doesn't show up immediately (or never), refer to zirinisp's answer or do the heavy work in the background.
You need to add the UIActivityIndicatorView to something. You can add it to a UITableView header view. To do this you will need to provide your own custom view.
...
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
[view addSubview:ac]; // <-- Your UIActivityIndicatorView
self.tableView.tableHeaderView = view;
...
There's workaround for UIViewController. (You can use a UIViewController with a table view to achieve a UITableViewController.) In storyboard, add a activityIndicator in the view of UIViewController. Then in viewDidLoad, add following:
[self.activityIndicator layer].zPosition = 1;
The activityIndicator will be displayed over the table view.
I have been trying to find a solution for that and have read a lot of forums, but i did not get what I wanted. After understanding how the activity indicator and table view controller works I came up with the following solution.
For some reason if you try to start the activity indicator on the same thread with the tableReload or any other expensive process, the activity indicator never runs. If you try to run table reload or some other operation in another thread then it might not be safe and might produce error or unwanted results. So we can run the method that presents the activity indicator on another thread.
I have also combined this solution with the MBProgressHUD to present something that look nicer that a view with an activity indicator. In any case the looks of the activityView can be customized.
-(void)showActivityViewer
{
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
UIWindow *window = delegate.window;
activityView = [[UIView alloc] initWithFrame: CGRectMake(0, 0, window.bounds.size.width, window.bounds.size.height)];
activityView.backgroundColor = [UIColor blackColor];
activityView.alpha = 0.5;
UIActivityIndicatorView *activityWheel = [[UIActivityIndicatorView alloc] initWithFrame: CGRectMake(window.bounds.size.width / 2 - 12, window.bounds.size.height / 2 - 12, 24, 24)];
activityWheel.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhite;
activityWheel.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleBottomMargin);
[activityView addSubview:activityWheel];
[window addSubview: activityView];
[[[activityView subviews] objectAtIndex:0] startAnimating];
}
-(void)hideActivityViewer
{
[[[activityView subviews] objectAtIndex:0] stopAnimating];
[activityView removeFromSuperview];
activityView = nil;
}
- (IBAction)reloadDataAction:(id)sender {
[NSThread detachNewThreadSelector:@selector(showActivityViewer) toTarget:self withObject:nil];
//... do your reload or expensive operations
[self hideActivityViewer];
}
[IOS 8+] The above does not work for me. Instead I store the indicator view (ac) in the class. Then I do:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (ac.isAnimating)
return 50.0f;
return 0.0f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (ac.isAnimating)
return ac;
return nil;
}
For showing the indicatorview I do
[ac startAnimating]
For hiding it, I do
[ac stopAnimating]