UIActivityIndicatorView does not show - ios

I have an app with a table view controller in which a user selects a US state, a web service is called and data is displayed for that state in the destination table view controller. Since the web service can take some time to complete I want an activity indicator. Since there will be no temporary data to display, I need this to be processed synchronously. So my task is pretty simple: start the activity indicator, call the web service, and after it completes, stop the activity indicator.
I am obviously doing something wrong and no activity indicator ever displays.
Here is the code from my destination table view controller's viewDidAppear method:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self.tableView bringSubviewToFront:spinner];
spinner.hidesWhenStopped = YES;
spinner.hidden = NO;
[spinner startAnimating];
stateGauges = [[GaugeList alloc] initWithStateIdentifier:stateIdentifier andType:nil];
[self.tableView reloadData];
[spinner stopAnimating];
}
Header:
#property (strong, nonatomic) UIActivityIndicatorView *spinner;
GaugeList is the object which makes the web service call.
Can someone tell me how to get an activity indicator view to appear? Thanks!

You forgot to add spinner on table view. Your code should look as follows:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spiner.center = //set some center
[self.tableView addSubview: spinner];
[self.tableView bringSubviewToFront:spinner];
spinner.hidesWhenStopped = YES;
spinner.hidden = NO;
[spinner startAnimating];
stateGauges = [[GaugeList alloc] initWithStateIdentifier:stateIdentifier andType:nil];
[self.tableView reloadData];
[spinner stopAnimating];
}
Also you send requests to a web service in main thread. This is bad practice. I would suggest something like following:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spiner.center = //set some center
[self.tableView addSubview: spinner];
[self.tableView bringSubviewToFront:spinner];
spinner.hidesWhenStopped = YES;
spinner.hidden = NO;
[spinner startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
stateGauges = [[GaugeList alloc] initWithStateIdentifier:stateIdentifier andType:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
[spinner stopAnimating];
});
});
}

At first you should add activity indicator to some view to show it. But you can not add it to UITableView, because UITableView is subclass of UIScrollView and you will see floating activity indicator. The best way in your case is to add activity indicator to navigation bar, etc. Or if you want to disable table view you should write something like this:
- (void)viewDidLoad {
[super viewDidLoad];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
UIView *dummyView = [[UIView alloc] init];
dummyView.frame = self.tableView.bounds;
dummyView.alpha = 0.5f;
dummyView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
dummyView.userInteractionEnabled = YES;
dummyView.backgroundColor = [UIColor blackColor];
[dummyView addSubview:activityIndicator];
activityIndicator.center = dummyView.center;
[self.tableView addSubview:dummyView];
}

Try using self.spinner instead of using spinner.

Related

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.
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.
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
fix it
[self performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];

iOS activity indicator issue

I am creating a UITableview inside a subview. For populating table I am using some jsonget request. During the process I want to show an activity indicator. I am not getting why it's not showing.
Sample code:
activityIndicator1 = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicator1.center = CGPointMake([[UIScreen mainScreen]bounds].size.width/2, [[UIScreen mainScreen]bounds].size.height/3);
[self.window addSubview:activityIndicator1];
activityIndicator1.color=[UIColor greenColor];
[self bringSubviewToFront:activityIndicator1];
[UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;
[activityIndicator1 startAnimating];
Problem is activity indicator not showing.
Thanks and Regards
Vikas
You need to add activityIndicator1 in your subvview.
i.e.
[self.subView addSubView: activityIndicator1];
activityIndicator1's center should be your subview's center.
activityIndicator1.center = subView.center;
Hope this helps.
Thanks
UIActivityIndicator's hidesWhenStopped property is YES by default. Also, it's stopped by default. So your activity indicator is just hidden. Add this code:
activityIndicator1.hidden = NO;
do this instead
UIView* WaitingView=[[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width,self.view.frame.size.height)];
WaitingView.backgroundColor=[UIColor blackColor];
WaitingView.alpha=0.5;
UIActivityIndicatorView* activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:
UIActivityIndicatorViewStyleWhiteLarge ];
[activityView setCenter:CGPointMake(self.view.frame.size.width/2,self.view.frame.size.height/2)];
[activityView setContentMode:UIViewContentModeCenter];
[WaitingView addSubview:activityView];
[self.view addSubview:WaitingView];
[activityView startAnimating];
When you're refreshing a table with fresh data from an api request, a common and handy tool is UIRefreshControl, which will show as an ActivityIndicator spinning, when the user pulls the table to refresh, while making the call to pull the fresh data.
#property (strong, nonatomic) UIRefreshControl *refreshControl;
then within your viewDidLoad create the refreshControl and add the target action
-(void)viewDidLoad{
[super viewDidLoad]
self.refreshControl = [[UIRefreshControl alloc]init];
[self.refreshControl addTarget:self action:#selector(refreshTable) forControlEvents:UIControlEventValueChanged];
[yourTableView addSubview:self.refreshControl];
}
By pulling the table in a downward motion, the activity indicator will show and the call to refresh the table will be made.
-(void)refreshTable{
// Here your call to pull data from your API to refresh the data
// ** Your code here to pull in your JSON data and update your datasource **
//Once the data has been retrieved or failed to retrieve, call this to end the refreshing
[self.refreshControl endRefreshing];
}
if this is what you're trying to recreate, I hope this helps.
Note - user will need to pull the table in a downward 'pull-to-refresh' action to activate this of course
add this in your .h file,
#property(nonatomic, retain) UIActivityIndicatorView *indicator;
than add this code in your button click method,
indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicator.frame = CGRectMake(0.0, 0.0, 60.0, 60.0);
indicator.color = [UIColor colorWithRed:0.949 green:0.571 blue:0.558 alpha:1.000];
[indicator setBackgroundColor:[UIColor colorWithRed:1 green:1.000 blue:1 alpha:1.000]];
indicator.center = self.view.center;
[self.view addSubview:indicator];
[indicator bringSubviewToFront:self.view];
[UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;
[indicator startAnimating];
than stop indicator where you want using,
[indicator stopAnimating];
hope this will help you.

Continue loading view after method loads from external URL

I have a method to retrieve data from an external url, load it into an array from JSON format, and populate a UITableView. It works fine, but there is no indication to the user that something is happening while the data is downloaded.
- (void)viewDidLoad
{
[super viewDidLoad];
[self retrieveDataC];
}
Here is the code that I tried for viewDidLoad which adds a spinner animation while downloading. I'm attempting to put retrieveDataC on a background thread and when it completes, I would like the view to continue executing as though I didn't implement the multi-threading in the example above.
- (void)viewDidLoad
{
[super viewDidLoad];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinner.center = CGPointMake(160, 240);
[self.view addSubview:spinner];
[spinner startAnimating];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self retrieveDataC];
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
});
});
}
The loading spinner displays correctly for a brief moment, however after the process is done I'm left with a blank table as though I have not called [self retrieveDataC] to begin with. Any suggestions, advice? Am I setting up the background process correctly?
Thank you
EDIT:
Here's what ended up working -
- (void)viewDidLoad
{
[super viewDidLoad];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(160, 240);
[self.view addSubview:spinner];
[spinner startAnimating];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self retrieveDataC];
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
[self.collectionView reloadData];
});
});
}
Do you call [self.tableView reloadData] after you received the data?

Load feedback in a TableView

I load a RSS feed into a TableView. Before it is loaded, it displays a empty tableview.
Can I let a activity indicator show until it is loaded?
Current code looks like this :
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleGray)];
[self.view addSubview:self.activityIndicator];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
[view addSubview:self.activityIndicator];
self.tableView.tableHeaderView = view;
dispatch_sync(dispatch_get_main_queue(), ^
{
[self.tableView reloadData];
//Remove load feedback
});
}
This code doesn't show anything I don't know why I expected to have a loading animation at the top but instead a empty space is added at the top of the tableview
The code you've presented puzzles me a bit. I think what you should do is present the activity indicator in the parserDidStartDocument method and remove it in parserDidEndDocument. I suggest creating another UIView property, name it activityIndicatorView, and do something like this:
- (void)parserDidStartDocument:(NSXMLParser *)parser {
if (!self.activityIndicatorView) {
self.activityIndicatorView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 60)];
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleGray)];
self.activityIndicator.center = CGPointMake(self.activityIndicatorView.frame.size.width/2,self.activityIndicatorView.frame.size.height/2);
[self.activityIndicatorView addSubview:self.activityIndicator];
}
self.tableView.tableHeaderView = self.activityIndicatorView;
[self.activityIndicator startAnimating];
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
[self.tableView reloadData];
[self.activityIndicator stopAnimating];
self.tableView.tableHeaderView = nil;
}
I don't know what your project looks like, but I assume you're doing something with the parsed document before reloading the table.
For this just add MBProgressHUD.h and MBProgressHUD.m into your project. Now to show indecator just write:
[MBProgressHUD showHUDAddedTo:self.view.window animated:YES];
and to hide write:
[MBProgressHUD hideAllHUDsForView:self.view.window animated:YES];
you can get classes from here

UIActivityIndicator Not Showing After WebService Has Been Called

In my application, I need to show a UIActivityIndicator while waiting for response from web service. I am using the following code:
UIView *loadView = [[UIView alloc] initWithFrame:self.view.bounds];
loadView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5];
//UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] init];
//[second.loadingView addSubview:activityView];
//activityView.center = second.loadingView.center;
//[second.view addSubview:second.loadingView];
UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[loadView addSubview:activity];
activity.center = loadView.center;
[self.view addSubview:loadView];
[self.view bringSubviewToFront:loadView];
activity.hidesWhenStopped = YES;
[activity setHidden:NO];
[activity startAnimating];
// calling My web service
[self callRegisterWebService:self.userFname lastName:self.userLName email:self.userEmail];
[activity stopAnimating];
[loadView setHidden:YES];
However, the indicator does not show up..!! What am i doing wrong??
You are probably waiting for the http response on the main thread. Try to implement the registration with dispatch_async function like this:
[activity startAnimating];
// calling My web service
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self callRegisterWebService:self.userFname lastName:self.userLName email:self.userEmail];
[activity stopAnimating];
});

Resources