show animation and locking the current view - ios

I have a method which is calling a external webservice.
Now I want to show an UIActivityIndicatorView in the middle of the screen, while the webservice-call is running. I call the webservice-method asynchronously. But with my code which you will find at the bottom, I have two problems:
the current view is not locked. That means, that the user can interact with the current view. I want to block all till the animation is stopped
the animation is not centered
Here is my code which I have tried now:
-(void)saveDataOnServer {
UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(225, 115, 30, 30)];
[activity setBackgroundColor:[UIColor clearColor]];
[activity setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
[self.view addSubview:activity];
[activity startAnimating];
// ...
[NSURLConnection sendAsynchronousRequest: request
queue: queue
completionHandler: ^(NSURLResponse *response, NSData *data, NSError *error) {
[activity stopAnimating];
// ...
}
];
}

You have to put another view when activity indicator start :
UIView *overlayView;
overlayView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
overlayView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
[[UIApplication sharedApplication].keyWindow addSubview:overlayView];
And remove that view(overlayView) when activity indicator stops :
[overlayView removeFromSuperview];
This OverlayView will cover current view.So user can not interact with current view.

Hi there i have a good solution for you ..
there i a library called MBProgressHUD
which does all you want , WITH Style
This is The link for the library HERE
And its easy to use .. here is an example i used
self.hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
self.hud.mode = MBProgressHUDModeIndeterminate;
self.hud.labelText = #"Fetching News";
//self.hud.detailsLabelText=#"Fetching News";
self.hud.dimBackground = YES;
and there is a demo you can see .. Cheers :D

Related

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.

UIActivityIndicatorView subview disappears before NSOperationQueue is finished

I'm trying to get a UIActivityIndicatorView to show on screen while my CSV import method is running, but I can't get it right. With the code below, the ActivityIndicator subview shows for a second or so then disappears, even if the import operation is still running. How can I make it stay on screen until the NSOperationQueue is finished? I'm using iOS 7.1 on my test device.
User taps 'Yes' on an UIAlertView to import the data:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if(buttonIndex == 0){
//clicked Yes
[self loadingSpinner];
operationQueue = [NSOperationQueue new];
NSInvocationOperation *importOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(importCSVData:) object:self.importURL];
[operationQueue addOperation:importOperation];
}
else if(buttonIndex == 1){
//clicked No
}
}
Method to show a UIActivityIndicatorView on top of everything else on screen:
-(void)loadingSpinner{
self.overlayView = [[UIView alloc] init];
self.overlayView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
UIView *topView = [UIApplication sharedApplication].keyWindow.rootViewController.view;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
self.overlayView.frame = [UIScreen mainScreen].bounds;
}
else{
self.overlayView.frame = topView.frame;
}
[self.overlayView setUserInteractionEnabled:NO];
self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
self.spinner.center = self.overlayView.center;
[self.overlayView addSubview:self.spinner];
[self.spinner startAnimating];
[topView addSubview:self.overlayView];
}
At the end of the import operation to remove the activity indicator:
[self.overlayView removeFromSuperview];
Use addOperationWithBlock: method on NSOperationQueue with which you will have more control. You would edit your code like this to use block version,
NSOperationQueue *queue = [NSOperationQueue new];
[queue addOperationWithBlock:^{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self loadingSpinner];
}];
[self importCSVData:self.importUrl];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self.overlay removeFromSuperView];
}];
}];
You can also use GCD to implement this task.
Create dispatch queue:
dispatch_queue_t queue = dispatch_queue_create("Other Q", NULL);
or you can use the main queue like:
dispatch_get_main_queue()
Finally replace your code with the following:
dispatch_async(queue, ^{
dispatch_sync(dispatch_get_main_queue(),^{
[self loadingSpinner];
});
[self importCSVData:self.importURL];
});
You might want to check for the title of you button clicked on your UIAlertView.
To do so change this:
if(buttonIndex == 1)
With this:
if([[alertView buttonTitleAtIndex:buttonIndex]isEqual:#"YES"])
Let me know if this helps.

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];
});

change UI at runtime from view controller

I have a view controller that loads a custom view(which in turn draws UI elements, then spawns a thread to do some things in the back ground.
If the "things that run in the background", encounter an error, my view controller catches it, and at this time I want to change UI elements, like bgcolor or add a new label.
But any changes I make are not showing up. This is what I'm trying:
[self performSelectorOnMainThread:#selector(onCompleteFail) withObject:nil waitUntilDone:YES];
- (void)onCompleteFail
{
NSLog(#"Error: Device Init Failed");
mLiveViewerView.backgroundColor= [UIColor whiteColor];
//self.view.backgroundColor = [UIColor whiteColor];
UILabel *tmpLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 200, 30)];
tmpLabel.text = #"Failed to init";
[self.view addSubview:tmpLabel];
}
You need to make any UI-related calls on the main thread: UIKit is not thread-safe and you’ll see all kinds of weird behavior from acting as if it is. That could be as simple as switching something from
[self onCompleteFail];
to
[self performSelectorOnMainThread:#selector(onCompleteFail) withObject:nil waitUntilDone:NO];
…or if -onCompleteFail has to be called on the background thread for other reasons, you can wrap your UI calls in a dispatch to the main queue, like this:
- (void)onCompleteFail
{
NSLog(#"Error: Device Init Failed");
dispatch_async(dispatch_get_main_queue(), ^{
mLiveViewerView.backgroundColor= [UIColor whiteColor];
//self.view.backgroundColor = [UIColor whiteColor];
UILabel *tmpLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 200, 30)];
tmpLabel.text = #"Failed to init";
[self.view addSubview:tmpLabel];
});
}

UIActivityIndicatorView does not show

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.

Resources