I am using MBProgressHUD for showing loading while performing local long method to put user good experience. All working fine but now i have to implement like that if the method executes within a second than the loading should not be appear. I have gone through the MBProgressHUD samples and for this functionality i found the setGraceTime and setMinShowTime show time but its all not working properly. because when i put set grace time the loading icon is not appear even the method execution time is more than 1 second.Here is my code
if (self.HUD == nil)
{
self.HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:self.HUD];
}
self.HUD.labelText = #"Please wait.....";
// [self.HUD setMinShowTime:2.0f];
[self.HUD setGraceTime:1.0f];
[self.HUD setTaskInProgress:YES];
[self.HUD show:YES];
// [self.HUD hide:YES afterDelay:3];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantPast]];
if (mycondition == nil)
{
[self myTask:[NSURL fileURLWithPath:strPath]];
//[self performSelector:#selector(mytask:) withObject:[NSURL fileURLWithPath:strPath]];
}
else
{
//else
}
self.tempView.hidden = YES;
// self.HUD.taskInProgress = NO;
[self.HUD hide:YES];
self.HUD = nil;
I have putted [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantPast]]; for this problem's solution
please guide me what wrong in this code..?!
You need to remove the MBProgressHUD object from its superview in the method execution.
Like this:
// if the method runs inside one second, the indicator will not be
shown
- (void)viewDidLoad
{
[super viewDidLoad];
if (HUD == nil)
{
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
}
HUD.labelText = #"Please wait.....";
[HUD setGraceTime:1.0f];
[HUD setTaskInProgress:YES];
[HUD show:YES];
[self performSelector:#selector(runThisMethod) withObject:nil afterDelay:0.9f];
}
- (void)runThisMethod
{
[HUD removeFromSuperview];
}
// if the method runs after one second, the indicator will be
shown for some time until the method runs
- (void)viewDidLoad
{
[super viewDidLoad];
if (HUD == nil)
{
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
}
HUD.labelText = #"Please wait.....";
[HUD setGraceTime:1.0f];
[HUD setTaskInProgress:YES];
[HUD show:YES];
[self performSelector:#selector(runThisMethod) withObject:nil afterDelay:1.9f];
}
- (void)runThisMethod
{
[HUD removeFromSuperview];
}
Related
I would like to display a hud while the content is loading (and show the progress), but unfortunately it doesn't work properly. The hud appears on the screen when statusUpdate is 0.100000, but the loading bar doesn't moves until statusUpdate is not 1.000000 and the page loading finished. (After the view loaded sucessfully it animates from 0-100%.) I would appreciate if somebody could show me what I'm doing wrong.
// ViewDidLoad
[self.webView addObserver:self forKeyPath:#"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.mode = MBProgressHUDModeDeterminateHorizontalBar;
HUD.delegate = self;
HUD.labelText = #"Uploading";
[HUD show:YES];
[self hud:self.webView.estimatedProgress];
if ([keyPath isEqualToString:#"estimatedProgress"] && object == self.webView) {
// [self.progressView setAlpha:1.0f];
// [self.progressView setProgress:self.webView.estimatedProgress animated:YES];
NSLog(#"%f", self.webView.estimatedProgress);
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
NSLog(#"%f", self.webView.estimatedProgress);
}
}
- (void) hud: (double)statusUpdate {
NSLog(#"STATUS %f", statusUpdate);
int myInt = (int)statusUpdate;
HUD.progress = (float)myInt;
}
Unless I'm missing something, the problem is on - (void) hud: (double)statusUpdate
For some reason you're casting the value (statusUpdate which is a double) to int and then again to a float, which means that 0.x values become 0.0 and 1.x values become 1.0 (that's why these are the only values that HUD is getting - since your range is 0.0/1.0)
A simple fix would be something like this:
- (void) hud: (double)statusUpdate {
NSLog(#"STATUS %f", statusUpdate);
HUD.progress = statusUpdate;
}
here is how i used it before:
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:vc.view animated:YES];
hud.mode = MBProgressHUDModeAnnularDeterminate;
hud.progress = 0;
hud.labelText = NSLocalizedString(#"Loading...", nil);
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
CGFloat progressValue = ((CGFloat)totalBytesRead/(CGFloat)totalBytesExpectedToRead);
MBProgressHUD *hud = [MBProgressHUD HUDForView:vc.view];
hud.progress = progressValue;
}];
Maybe you can create something like animation using CADisplayLink. It will update your HUD.
#interface ViewController () {
CADisplayLink *displayLink;
}
- (void)displayLinkMethod {
displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(animationMethod)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
I'm using a method for scanning Bluetooth device, which I import from another framework. The scanning method would take a while, and it'll block the GUI, which is what we never want to happen.
I'm also having MBProgressHud, trying to show a hud while scanning, but it's not working (hud not showing up). Any help?
Here's the code I'm currently using:
[hud showAnimated:YES whileExecutingBlock:^{
self.btDevices = [Util scanBT];
}];
Edit 1: Okay, so if I use this code, it'll still block my UI for a while, then all suddenly continue to run.
hud = [[MBProgressHUD alloc] initWithView:self.view];
hud.labelText = #"Now scanning";
hud.dimBackground = YES;
hud.opacity = 0.5;
[hud show:YES];
[hud hide:YES afterDelay:5.0];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.001 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void){
self.btDevices = [Util scanBT];
});
Edit 2: Ok, I will post all my block of code:
hud = [[MBProgressHUD alloc] initWithView:[self getTopView:self.view]];
hud.labelText = #"Now scanning";
hud.dimBackground = YES;
hud.opacity = 0.5;
[hud showAnimated:YES whileExecutingBlock:^{
self.btDevices = [Util scanBT];
}];
dispatch_queue_t myqueue = dispatch_queue_create("queue", NULL);
dispatch_async(myqueue, ^{
//Whatever is happening in the BT scanning method will now happen in the background
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:[self getTopView:self.view] animated:YES];
});
});
/** Recursion to get the top most view in view layer. */
- (UIView *)getTopView:(UIView *)view
{
if ([view.superview class]) {
return [self getTopView:view.superview];
}
return view;
}
I'm request scanning bt in a popover, but I want to show HUD in a main View, so I write a block to retrieve the main view. Maybe that's where the problem occur?
Try this:
In your viewDidload or the method where you want to place it
MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:self.view];
[hud setDimBackground:YES];
[hud setOpacity:0.5f];
[hud show:YES];
[hud hide:YES afterDelay:5.0];
[self performSelector:#selector(startScanning) withObject:nil afterDelay:5.0];
And your method
- (void) startScanning {
self.btDevices = [Util scanBT];
}
OR I think you should try it running
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.001 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void){
// Insert task code here
self.btDevices = [Util scanBT];
});
Try it with completion block
[hud showAnimated:YES whileExecutingBlock:^{
self.btDevices = [Util scanBT];
} completionBlock:^{
//code for after completion
}];
OR you can also try this
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
dispatch_queue_t myqueue = dispatch_queue_create("queue", NULL);
dispatch_async(myqueue, ^{
//Whatever is happening in the BT scanning method will now happen in the background
self.btDevices = [Util scanBT];
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
});
"Warning: Attempt to dismiss from view controller while a presentation or dismiss is in progress!"
I'm trying to have my app go to a loading screen upon selecting a picture to upload. This works by, upon selecting a picture, removing the UIImagePickerController scene, adding the Loading scene, and once the upload is complete, removing the Loading scene.
-(void)uploadMessage{
[self dismissViewControllerAnimated:NO completion:nil];
LoadingViewController *loadView = [[LoadingViewController alloc]initWithNibName:#"LoadView" bundle:nil];
[self presentViewController:loadView animated:NO completion:^{
NSData *fileData;
NSString *fileName;
NSLog(#"Image");
fileData = UIImagePNGRepresentation(self.image);
fileName = #"image.png";
PFFile *file = [PFFile fileWithName:fileName data:fileData];
[self.game setObject:file forKey:#"picture"];
[self.game saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if(succeeded){
[self removeAndChangeButtons];
[self dismissViewControllerAnimated:NO completion:nil];
}
}];
}];
}
You can add a function using MBProgressHUD.
- (void) showMessage:(NSString*)message withTitle:(NSString*)title onView:(UIView*)view removeAfter:(NSTimeInterval)delay{
dispatch_async(dispatch_get_main_queue(), ^{
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:view animated:YES];
// Configure for text only and offset down
hud.mode = MBProgressHUDModeText;
hud.labelText = title;
hud.detailsLabelText = message;
hud.margin = 10.f;
hud.yOffset = 0.0f;
hud.removeFromSuperViewOnHide = YES;
[hud hide:YES afterDelay:delay];
});
}
Then in your code when you start the background task, call showMessage and then the upload is done, remove it.
You are dismissing the ViewController twice in your method if it is successful. Obviously, this can't be done. I don't know what exactly what you're trying to achieve, but I think removing the first [self dismissViewControllerAnimated:NO completion:nil] would do the trick.
I'm using MBProgressHUD in our teaching App, which is tab bar navigated.
The user will come from a tableview via Urban Airship's storefront directly to the UA detail view.
Once buy is clicked I bring on HUD with
HUD = [[MBProgressHUD alloc] initWithWindow:[UIApplication sharedApplication].keyWindow];
[self.view.window addSubview:HUD];
It is using the showWhileExecuting statement.
It goes through three while statements to change from "Connecting" to "Downloading" to "Unpacking".
All working perfectly OK.
Here comes the problem...
The second time I do this the label text will not change. It is stuck on "Connecting".
I can see in the NSLog that it is going through the other loops.
On top of that, if I try to change the Mode, the app crashes.
This only happens the second time, and any subsequent uses. If I kill the App everything works again for the first time.
Looks to me that MBProgressHUD doesn't get reset when it's finished.
(ARC is used in the project)
Anyone with a solution?
Thanks
Edit:
- (void)showWithLabelDeterminate
{
HUD = [[MBProgressHUD alloc] initWithWindow:[UIApplication sharedApplication].keyWindow];
HUD.mode = MBProgressHUDModeIndeterminate;
[self.view.window addSubview:HUD];
HUD.delegate = self;
HUD.labelText = NSLocalizedString(#"Connecting","");
HUD.detailsLabelText = #" ";
HUD.minSize = CGSizeMake(145.f, 145.f);
HUD.dimBackground = YES;
[HUD showWhileExecuting:#selector(lessonDownloadProgress) onTarget:self withObject:nil animated:YES];
}
-(void)lessonDownloadProgress
{
DataManager *sharedManager = [DataManager sharedManager];
// HUD.mode = MBProgressHUDModeIndeterminate;
HUD.labelText = nil;
HUD.detailsLabelText = nil;
while ([sharedManager.downHUD floatValue] == 0.0f)
{
[self parentViewController];
NSLog(#"HUD lessonDownloadProgress: %f", HUD.progress);
HUD.labelText = NSLocalizedString(#"Connecting","");
HUD.detailsLabelText = #" ";
NSLog(#"Waiting for download to start");
// Wait for download to start
usleep(80000);
}
// Switch to determinate mode
// HUD.mode = MBProgressHUDModeDeterminate;
HUD.labelText = NSLocalizedString(#"DownLoading","");
HUD.progress = [sharedManager.downHUD floatValue];
while (HUD.progress < 1.0f && [sharedManager.cleanedUp isEqualToString:#"No"])
{
// [self parentViewController];
HUD.labelText = NSLocalizedString(#"Downloading","");
NSLog(#"HUD lessonDownloadProgress: %f", HUD.progress);
HUD.progress = [sharedManager.downHUD floatValue];
NSString *percent = [NSString stringWithFormat:#"%.0f", HUD.progress/1*100];
HUD.detailsLabelText = [percent stringByAppendingString:#"%"];
usleep(50000);
}
// Switch HUD while cleanUp
HUD.mode = MBProgressHUDModeIndeterminate;
while ([sharedManager.cleanedUp isEqualToString:#"No"])
{
[self parentViewController];
HUD.labelText = NSLocalizedString(#"Unpacking","");
HUD.detailsLabelText = #" ";
// wait for cleanup
NSLog(#"Waiting for clean up");
usleep(50000);
}
NSLog(#"++ Finished loops ++");
NSLog(#"Finished HUD lessonDownloadProgress: %f", HUD.progress);
[MBProgressHUD hideHUDForView:self.view animated:YES];
[HUD removeFromSuperview];
HUD.delegate = nil;
[HUD release];
HUD = nil;
}
I cannot spot the issue in the code you posted; but some refactoring might help.
Rather than polling the DataManager you could use KVO to observe properties on the DataManager and respond to those changes. ("Don't call us; we'll call you.) So here's a suggested approach if you want.
Your class interface:
#interface YourClass : UIViewController // or whatever your superclass is...
{
MBProgressHUD *_hud;
DataManager *_dataManager;
// your other ivars
}
#end
And in your implementation file...
#interface YourClass()
#property (nonatomic, retain) DataManager dataManager;
#end
Above I've declared your dataManager as a property so that we can observe it.
To start the download process we now have a method downloadLesson:
- (void)downloadLesson;
{
// show HUD and retain it (showHUDAddedTo:animated: returns autoreleased object)
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES] retain];
// observe properties on the dataManager
[self addObserver:self forKeyPath:#"dataManager.progress" options:NSKeyValueObservingOptionNew context:nil];
[self addObserver:self forKeyPath:#"dataManager.cleanedUp" options:NSKeyValueObservingOptionNew context:nil];
[self addObserver:self forKeyPath:#"dataManager.downHUD" options:NSKeyValueObservingOptionNew context:nil];
// begin your download here...
HUD.labelText = NSLocalizedString(#"Connecting", "");
HUD.detailsLabelText = #" ";
HUD.progress = self.dataManager.downHUD;
}
Now use KVO to update the appearance of the HUD:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
{
if( [keyPath isEqualToString:#"dataManager.cleanedUp"] )
{
if( [[[self dataManager] cleanedUp] isEqualToString:#"Yes"] )
{
[MBProgressHUD hideHUDForView:[[UIApplication sharedApplication] keyWindow] animated:YES];
[HUD release]; HUD = nil;
[self removeObserver:self forKeyPath:#"dataManager.progress"];
[self removeObserver:self forKeyPath:#"dataManager.cleanedUp"];
[self removeObserver:self forKeyPath:#"dataManager.downHUD"];
}
}
if( [keyPath isEqualToString:#"dataManager.downHUD"] )
{
// if the data manager updates progress, update our HUD
HUD.progress = self.dataManager.downHUD;
if( self.dataManager.downHUD == 0.0 )
// no progress; we're just connecting
HUD.labelText = NSLocalizedString(#"Connecting", "");
else if( self.dataManager.downHUD < 1.0 )
{
// progress >0.0 and < 1.0; we're downloading
HUD.labelText = NSLocalizedString(#"Downloading", "");
NSString *percent = [NSString stringWithFormat:#"%.0f%%", HUD.progress/1*100];
HUD.detailsLabelText = percent;
}
else
{
// progress == 1.0, but we haven't cleaned up, so unpacking
if( [[[self dataManager] cleanedUp] isEqualToString:#"No"] )
{
HUD.labelText = NSLocalizedString(#"Unpacking","");
HUD.detailLabelsText = #" ";
}
}
}
}
Alternatively, you could use notifications to do the updates, wherein the DataManager posts NSNotifications for which your view controller is registered. Or, if you were open to refactoring the DataManager you could use blocks to do the updates. All of these solutions avoid having to explicitly block your thread to poll the DataManager. Hope this helps.
Did you implement the delegate method?
- (void)hudWasHidden:(MBProgressHUD *)hud {
// Remove HUD from screen when the HUD was hidded
[HUD removeFromSuperview];
HUD = nil;
}
This is because the label is set up on init.Try this:
You should just add this method to the header file of MBProgressHud:
+ (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view withText:(NSString *)text;
And implement it in the .m file as follows:
+ (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view withText:(NSString *)text
{
MBProgressHUD *hud = [[self alloc] initWithView:view];
hud.labelText = text;
[view addSubview:hud];
[hud show:YES];
return MB_AUTORELEASE(hud);
}
and call it wherever you want like:
[MBProgressHUD showHUDAddedTo:self.view withText:#"Loading..."];
i am able to show HUD indicator in viewDidLoad successfully but not able hide it in webViewDidFinishLoad method when webview is completely loaded. Please help.
i am using below code::
in .h file
MBProgressHUD *HUD;
in viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *query = [[NSString alloc] initWithFormat:#"http://localhost/index.php?uid=%#", [[UIDevice currentDevice] uniqueIdentifier]];
NSURL *url = [[NSURL alloc] initWithString:query];
NSString *response = [[NSString alloc] initWithContentsOfURL:url];
if(response)
{
[webView loadRequest:[NSURLRequest requestWithURL:url]];
}
else
{
//NSLog(#"err %#",response);
}
HUD = [[MBProgressHUD showHUDAddedTo:self.view animated:YES] retain];
HUD.delegate = self;
HUD.labelText = #"loading";
}
and in webViewDidFinishLoad
- (void)webViewDidFinishLoad:(UIWebView *)web
{
[HUD hide:TRUE]; //it does not work for me :(
}
i have fixed the error, i moved the code from viewDidLoad to webViewDidStartLoad and everything is working fine this time :)
- (void)webViewDidStartLoad:(UIWebView *)web
{
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"loading";
}
- (void)webViewDidFinishLoad:(UIWebView *)web
{
[MBProgressHUD hideHUDForView:self.view animated:YES];
}
try with this one
[HUD hide:YES];
if(HUD!=nil && [HUD retainCount]>0)
{
[HUD removeFromSuperview];
[HUD release];
HUD=nil;
}
You should not call MBProgressHUD from viewDidLoad, try calling it from viewDidAppear and everything should work well.
Try removing it using this class method:
+ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated
.
- (void)webViewDidFinishLoad:(UIWebView *)web
{
[MBProgressHUD hideHUDForView:self.view animated:YES];
}
If you use this method then you should think about rewriting your viewDidLoad this way:
- (void)viewDidLoad
{
[super viewDidLoad];
//...
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"loading";
}