tech_human tech_human - 12 days ago 9
Objective-C Question

Disabling selection in the background when activity indicator is present

I am adding activity indicator on top of the view and wish to disable the selections in the background when the activity indicator is on. Also for some reason, my activity indicator is still spins for about 30-45 seconds(depending on the network speed) after the data is displayed on the table view. I have created a category for activity indicator.

Activity Indicator category code:

- (UIView *)overlayView {
return objc_getAssociatedObject(self, OverlayViewKey);
}

- (void)setOverlayView:(UIView *)overlayView {
objc_setAssociatedObject(self, OverlayViewKey, overlayView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (void)showActivityIndicatorForView:(UIView *)view {
self.overlayView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
self.center = self.overlayView.center;
[view setUserInteractionEnabled:NO];
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
[self.overlayView setUserInteractionEnabled:NO];
[self startAnimating];
[self.overlayView addSubview:self];
[view addSubview:self.overlayView];
[view bringSubviewToFront:self.overlayView];
self.hidesWhenStopped = YES;
self.hidden = NO;

}

- (void)hideActivityIndicatorForView:(UIView *)view {
[self stopAnimating];
[self.overlayView setUserInteractionEnabled:YES];
[self.overlayView removeFromSuperview];
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
[view setUserInteractionEnabled:YES];
}


Usages in table view controller:

@interface MyTableViewController()
@property (nonatomic, strong) UIActivityIndicatorView *activityIndicator;
@end

@implementation MyTableViewController
- (id) initWithSomething:(NSString *)something {
self = [super init];

if (self) {
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
self.activityIndicator.overlayView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
}
return self;
}

- (void)viewDidLoad {
[super viewDidLoad];

[self getDataServiceRequest];
[self.activityIndicator showActivityIndicatorForView:self.navigationController.view];
}

- (void)requestCompletionCallBack sender:(ServiceAPI *)sender {
// Do something here with the data
[self.activityIndicator hideActivityIndicatorForView:self.navigationController.view];

dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
@end


What am I doing wrong here? Why am I still able to select the data in the background when the activity indicator is on and even after disabling the user interaction.

Answer

Move your call to hideActivityIndicatorForView to inside the call to dispatch_async(dispatch_get_main_queue(). It's a UI call, and needs to be done on the main thread.

As for how to disable other actions on your view controller, you have a few options. One simple thing I've done is the put the activity indicator inside a view that's pinned to the whole screen, set to opaque=false, and with a color that's black with an alpha setting of 0.5. That way the content underneath is visible but the user can't click on it. You need to add an outlet to your "coveringView" and show-hide it instead of showing/hiding the activity indicator view.