i am playing around with MBProgressHUD. the worflow in the viewcontroller (tableview) goes like that:
1) IBAction gets called to switch between 2 different tables
2.1) function reloadAllMonth gets called (initializes an array with the data for the new table)
2.2) MBProgressHUD *HUD should be displayed
3) reloadAllMonth is finished
4) HUD should disappear
my current code:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//sparing you the code that determins where the tap occured
HUD = [[MBProgressHUD alloc]initWithFrame:self.view.frame];
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[self reloadAllMonth];
allMonthIsActive = YES;
[MBProgressHUD hideHUDForView:self.view animated:YES];
// some other code table reload etc.
}
what happens:
-> function touchesbegan gets called
-> nothing happens for 3-4 seconds (loading time)
-> new table pops up
question: why does the HUD not show up? where did i go wrong ?
You can't have both show and hide in the same thread, this is what I would do:
-(void)reloadStuff
{
[self reloadAllMonth];
allMonthIsActive = YES;
[MBProgressHUD hideHUDForView:self.view animated:YES];
isLoading = NO;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//sparing you the code that determins where the tap occured
if (isLoading)
return;
isLoading = YES;
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[self performSelectorInBackground:#selector(doStuff) withObject:nil];
}
Also you can remove the ivar HUD, you are not using it.
And don't forget to initialize isLoading in viewDidLoad to NO:
isLoading = NO;
Good luck!
Are u fetching anything from the server ?
If so please check whether u are passing synchronous request or asynchronous . Asynchronous requests are the best to follow .
Handle MBProgressBar in this way .
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
dispatch_async(dispatch_get_main_queue(), ^{
//Any UI updates should be made here .
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
Related
I have a UITableView and when I touch a row of its I call myFunction that perform any operation and then reload the table.
Now I want to show an UIActivityIndicator while I call myFunction. What is the approach followed in these cases?
This is my code:
-(void)collectionView:(UICollectionView*)collectionview didSelectItemAtIndexPath:(NSIndexPath*) indexPath {
[self showLoader];
[self performSelectorInBackground:#selector(myFunction:) withObject:indexPath];
[self hideLoader];
}
I prefer to use this MBProgressHUD.
This is good example for calling UIActivityIndicator while loading data.
Add some Delay in your Call :
-(void)collectionView:(UICollectionView*)collectionview didSelectItemAtIndexPath:(NSIndexPath*) indexPath
{
[self showLoader];
[self performSelector:#selector(myFunction:) withObject:indexPath afterDelay:1.0];
[self hideLoader];
}
GoodLuck...!!!
In This code UIActivityIndicator display in statusBar
-(void)collectionView:(UICollectionView*)collectionview didSelectItemAtIndexPath:(NSIndexPath*) indexPath {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self showLoader];
[self performSelector:#selector(myFunction:) withObject:indexPath afterDelay:1.0];
[self hideLoader];
}
and for stop UIActivityIndicator write following code at end of myFunction
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
Im using the MBProgressHUD to make an overview loading screen while logging out in my ipad app. That progress takes some time because I have to encrypt some bigger files.
Because Im doing it in a background thread and the MBProgressHUD is animating on the main thread, I had to do something to know when my background thread is finished.
As a test, I did it like that:
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDAnimationFade;
hud.labelText = #"Do something...";
[self performSelectorInBackground:#selector(doSomethingElse) withObject:nil];
And method doSomethingElse:
-(void)doSomethingElse
{
[self encrypt];
[self performSelectorOnMainThread:#selector(doSomethingElseDone) withObject:nil waitUntilDone:YES];
}
And method doSomethingElseDone:
-(void)logoutInBackgroundDone
{
[MBProgressHUD hideHUDForView:self.view animated:YES];
}
The solution works but I think there must be a better way? How can I do that on a better way?
Any help is really appreciated.
You can directly dismiss the MBProgressHUD from doSomethingElse method using dispatch_async
-(void)doSomethingElse
{
[self encrypt];
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
}
Create an atomic property you can get to
#property BOOL spinning;
and
- (void)myTask
{
while ( self.spinning )
{
usleep(1000*250); // 1/4 second
}
}
then use something in your view controller like
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
[HUD showWhileExecuting:#selector(myTask) onTarget:self withObject:nil animated:YES];
This way the HUD will remove itself when spinning becomes false. The spinner has to be atomic since it will be referenced in a background thread. Whatever you are waiting on can simply set the spinner property to false from any thread to indicate it's done.
This is under ARC.
I have this code that loads a new UIView (from storyboard) when a button is pressed. goPressed function is fired on button pressed and it calls selectImage function. selectImage opens a UIImagePickerController and lets user select a photo. After user has selected the photo, didFinishPickingMediaWithInfo delegate adds the selected image to a UIImageView.
In 'goPressed', after selectImage is performed, it should be performing a Segue at like commented as //1. But nothing happens. performSegueWithIdentifier doesn't seem to be working. And if I don't call [self selectImage] before calling performSegueWithIdentifier, it works. Here is the code:
- (IBAction)goPressed:(id)sender {
[self selectImage];
[self performSegueWithIdentifier:#"lastView" sender:currentSender]; //1
}
-(void)selectImage
{
// Create image picker controller
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
// Set source to the camera
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
// Delegate is self
imagePicker.delegate = (id)self;
// Allow editing of image ?
imagePicker.allowsEditing=NO;
// Show image picker
[self presentModalViewController:imagePicker animated:YES];
}
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Access the uncropped image from info dictionary
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[[picker presentingViewController] dismissModalViewControllerAnimated:YES];
lePreview.image= image;
}
Please help, why performSegueWithIdentifier isn't working? I hope I am not missing any information you need.
I'm assuming that the view you are trying to segue to is using the picture you get just before you do your segue? If they cancel from the image picker do you still want to segue?
If it needs the picture, then maybe you should call your segue after the delegate call "did finish picking".
The issue with the segue not firing may be due to the animation still occurring from here:
[[picker presentingViewController] dismissModalViewControllerAnimated:YES];
You can try:
[[picker presentingViewController] dismissModalViewControllerAnimated:NO];
or if you want to maintain the animation, move the segue to the "picker did finish" method and do it this way:
[self dismissModalViewControllerAnimated:YES completion:^() {
[self performSegueWithIdentifier:#"lastView" sender:self];
}];
or if that does not work try this approach in the pickerdidfinish method (note - this should be implemented as a delegate in the controller that calls the modal view, not the modal view itself:
//maintain the animation
[self dismissModalViewControllerAnimated:YES];
//slight pause to let the modal page dismiss and then start the segue
double delayInSeconds = 0.5;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//code to be executed on the main queue after delay
[self performSegueWithIdentifier:#"lastView" sender:self];
});
I use this transition frequently and it makes a nice drop away with the modal view then slides in the segue view and the pause allows the transition to seem natural.
I am using a UIActivityIndicatorView as an IBOutlet. I am trying to control it using [activityView startAnimating] and [activityView stopAnimating].
I have enabled 'Hides when stopped' and 'Animating' behaviors in XIB file.
I want to start animate the spinner for several user actions inside the controller. But after the first [activityView stopAnimating] call it does not response to [activityView startAnimating] call again.
That is mean the spinner is disappeared after the first [activityView stopAnimating] call.
I tried activeView.hidden = NO; before the next [activityView startAnimating] call. But it does not work.
Any idea about this issue?
Edited
After my controller loaded I do follow thing,
do {
[self.activityIndicator startAnimating];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[webServiceCallOperation getResults];
[self.activityIndicator stopAnimating];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
} while (![webServiceCallOperation isValideResponse] || [webServiceCallOperation isServerError]);
In the same controller I have a IBAction for a button click.
- (IBAction)tappedSearchButton:(id)sender
{
[self.activityIndicator startAnimating];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[self tappedSearchButtonAction];
[self.activityIndicator stopAnimating];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
I noticed that the spinner not begin to animate just after the [self.activityIndicator startAnimating]; call. Using [self tappedSearchButtonAction]; I call to a web service and go to the search results view. The spinner begin to animate just before change the view. That's why I did not see it. But I suppose to animate it before web service call and should animate it while my web service call.
Same behavior of the network activity indicator.
As aadhira suggested check for release and if you are making the calls on the main thread.
[NSObject performSelectorOnMainThread:#selector(SEL) withObject:nil waitUntilDone:YES];
It starts animating because as you say you have enabled Animating behavior in the XIB file. But after you stop it for the first time, it is not animating anymore until you start it again programatically.
when i click on button which title is click here to enlarge then i want show activity indicator on the first view and remove when load this view.
but i go back then it show activity indicator which is shown in this view.
in first vie .m file i have use this code for action.
-(IBAction)btnSelected:(id)sender{
UIButton *button = (UIButton *)sender;
int whichButton = button.tag;
NSLog(#"Current TAG: %i", whichButton);
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[spinner setCenter:CGPointMake(160,124)];
[self.view addSubview:spinner];
[spinner startAnimating];
if(whichButton==1)
{
[spinner stopAnimating];
first=[[FirstImage alloc]init];
[self.navigationController pushViewController:first animated:YES];
[spinner hidesWhenStopped ];
}}
in above code i have button action in which i call next view. Now i want show/display activity indicator when view upload. In next view i have a image view in which a image i upload i have declare an activity indicator which also not working. How do that?
Toro's suggestion offers a great explanation and solution, but I just wanted to offer up another way of achieving this, as this is how I do it.
As Toro said,
- (void) someFunction
{
[activityIndicator startAnimation];
// do computations ....
[activityIndicator stopAnimation];
}
The above code will not work because you do not give the UI time to update when you include the activityIndicator in your currently running function. So what I and many others do is break it up into a separate thread like so:
- (void) yourMainFunction {
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[NSThread detachNewThreadSelector:#selector(threadStartAnimating) toTarget:self withObject:nil];
//Your computations
[activityIndicator stopAnimating];
}
- (void) threadStartAnimating {
[activityIndicator startAnimating];
}
Good luck!
-Karoly
[self.navigationController pushViewController:first animated:YES];
Generally, when you push a view controller into navigation controller, it will invoke the -(void)viewWillAppear: and -(void)viewDidAppear: methods. You can add activity indicator view inside the viewWillAppear: and call startAnimation of indicator view. You CANNOT invoke startAnimation and stopAnimation at the same time. For example,
- (void)viewWillAppear:(BOOL)animated
{
[aIndicatorView startAnimation];
// do somethings ....
[aIndicatorView stopAnimation];
}
Because the startAnimation and stopAnimation are under the same time, then no animation will show.
But if you invoke startAnimation in -(void)viewWillAppear: and invoke stopAnimation in another message, like followings.
- (void)viewWillAppear:(BOOL)animated
{
[aIndicatorView startAnimation];
// do somethings...
}
- (void)viewDidAppear:(BOOL)animated
{
[aIndicatorView stopAnimation];
}
Because viewWillAppear: and viewDidAppear: are invoked with different event time, the activity indicator view will work well.
Or, you can do something like followings:
- (void)viewWillAppear:(BOOL)animated
{
[aIndicatorView startAnimation];
// Let run loop has chances to animations, others events in run loop queue, and ... etc.
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]];
// do somethings ....
[aIndicatorView stopAnimation];
}
The above example is a bad example, because it invokes two or more animations in the -runUntilDate:. But it will let the activity indicator view work.
Create a webview. Add a activity indicator to the webview. If you are loading a image via url into the webview then implement the webview delegate methods. Once the url is loaded then stopanimating the activity indicator.
Let me know which step you are not able to implement.