Use of MBProgressHUD Globally + make it singleton

17,273

Solution 1

You could add this to a class of your liking:

+ (MBProgressHUD *)showGlobalProgressHUDWithTitle:(NSString *)title {
    UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:window animated:YES];
    hud.labelText = title;
    return hud;
}

+ (void)dismissGlobalHUD {
    UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
    [MBProgressHUD hideHUDForView:window animated:YES];
}

This can be than called on any class. You don't need to keep a strong reference to the HUD when using those class convenience methods.

Depending on your specific situation you'll probably also want to handle cases where a new hud is requested before the other one is hidden. You could eater hide the previous hud when a new comes in or come up with some sort of queueing, etc.

Hiding the previous HUD instance before showing a new one is pretty straightforward.

+ (MBProgressHUD *)showGlobalProgressHUDWithTitle:(NSString *)title {
    UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
    [MBProgressHUD hideAllHUDsForView:window animated:YES];
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:window animated:YES];
    hud.labelText = title;
    return hud;
}

Solution 2

NOTE...

as with many iOS issues, this is now drastically, totally out of date.

These days you certainly just use a trivial

Container view

for any issue like this.

Full container view tutorial for beginners .. tutorial!

MBProgressHUD was a miraculous solution back in the day, because there was a "drastic hole" in Apple's pipeline.

But (as with many wonderful things from the past), this is only history now. Don't do anything like this today.


Just FWIW, 2014, here's a very simple setup we use. Per David Lawson...

UIWindow *window = [[UIApplication sharedApplication] delegate].window

as Matej says, just use AppDelegate...

#define APP ((AppDelegate *)[[UIApplication sharedApplication] delegate])

AppDelegate.h

// our convenient huddie system (messages with a hud, spinner)
@property (nonatomic, strong) MBProgressHUD *hud;
-(void)huddie;

AppDelegate.m

-(void)huddie
{
// centralised location for MBProgressHUD
[self.hud hide:YES];

UIWindow *windowForHud = [[UIApplication sharedApplication] delegate].window;
self.hud = [MBProgressHUD showHUDAddedTo:windowForHud animated:YES];

self.hud.dimBackground = YES;
self.hud.minShowTime = 0.1;
self.hud.labelText = @"";
self.hud.detailsLabelText = @"";
}

Set the titles in your code where you are using it - because you very often change them during a run. ("Step 1" ... "Step 2" etc)

-(void)loadBlahFromCloud
{
[APP huddie];
APP.hud.labelText = @"Connecting to Parse...";
APP.hud.detailsLabelText = @"step 1/2";

[blah refreshFromCloudThen:
    ^{
    [... example];
    }];
}

-(void)example
{
APP.hud.labelText = @"Connecting to the bank...";
APP.hud.detailsLabelText = @"step 2/2";

[blah sendDetailsThen:
    ^{
    [APP.hud hide:YES];
    [...  showNewDisplay];
    }];
}

Change huddle to take the texts as an argument if you wish

You always want self.hud.minShowTime = 0.1; to avoid flicker

Almost always self.hud.dimBackground = YES; which also blocks UI

Conceptually of course you usually have to "slightly wait" to begin work / end work when you bring up such a process, as with any similar programming with the UI.

So in practice code will usually look like this...

-(void)loadActionSheets
{
[APP huddie];
APP.hud.labelText = @"Loading json from net...";

dispatch_after_secs_on_main(0.1 ,
    ^{
    [STUBS refreshNowFromCloudThen:
        ^{
        [APP.hud hide:YES];
        dispatch_after_secs_on_main(0.1 , ^{ [self buildActionsheet]; });
        }];
        }
    );
}

Handy macro ..

#define dispatch_after_secs_on_main( SS, BB )                   \
        dispatch_after(                                         \
            dispatch_time(DISPATCH_TIME_NOW, SS*NSEC_PER_SEC),  \
            dispatch_get_main_queue(),                          \
            BB                                                  \
            )

This is all history now :) https://stackoverflow.com/a/23403979/294884

Solution 3

This answer is what I've been using for 5-6 Apps now because it works perfectly inside blocks too. However I found a problem with it. I can make it shown, but can't make it disappear if a UIAlertView is also present. If you look at the implementation you can see why. Simply change it to this:

static UIWindow *window;

+ (MBProgressHUD *)showGlobalProgressHUDWithTitle:(NSString *)title {

    window = [[[UIApplication sharedApplication] windows] lastObject];
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:window animated:YES];
    hud.labelText = title;

    return hud;
}

+ (void)dismissGlobalHUD {

    [MBProgressHUD hideHUDForView:window animated:YES];
}

This will make sure you're removing the HUD from the same windows as it was shown on.

Solution 4

I found @Matej Bukovinski 's answer very helpful, since I just started using Swift and my purpose using his methods was to set a global font for the MBProgressHUD, I have converted the code to swift and am willing to share the code below:

class func showGlobalProgressHUDWithTitle(title: String) -> MBProgressHUD{
    let window:UIWindow = UIApplication.sharedApplication().windows.last as! UIWindow
    let hud = MBProgressHUD.showHUDAddedTo(window, animated: true)
    hud.labelText = title
    hud.labelFont = UIFont(name: FONT_NAME, size: 15.0)
    return hud
}

class func dismissGlobalHUD() -> Void{
    let window:UIWindow = UIApplication.sharedApplication().windows.last as! UIWindow
    MBProgressHUD.hideAllHUDsForView(window, animated: true)
}

The above code is put into a global file where I keep all my global helpers and constants.

Solution 5

I've used it as below..Hope it helps you..

in appDelegate.m

-(void)showIndicator:(NSString *)withTitleString currentView:(UIView *)currentView
{ 
if (!isIndicatorStarted) {

    // The hud will dispable all input on the view
    self.progressHUD = [[[MBProgressHUD alloc] initWithView:currentView] autorelease]; 
    // Add HUD to screen 
    [currentView addSubview:self.progressHUD]; 
    self.progressHUD.labelText = withTitleString;
    [window setUserInteractionEnabled:FALSE];
    [self.progressHUD show:YES];

    isIndicatorStarted = TRUE;
}   
 } 

-(void)hideIndicator 
{ 

    [self.progressHUD show:NO]; 
    [self.progressHUD removeFromSuperview]; 
    self.progressHUD = nil;
    [window setUserInteractionEnabled:TRUE];
    isIndicatorStarted = FALSE;
}

From Random Views:-

[appDel showIndicator:@"Loading.." currentView:presentView.view];

Share:
17,273

Related videos on Youtube

viral
Author by

viral

iOS App Dev #SOreadytohelp

Updated on September 15, 2022

Comments

  • viral
    viral over 1 year

    In my Project, each of the user interaction events make a network call (Which is TCP, not HTTP). I need Activity Indicator to be global to show from a random UIViewController and hide from NetworkActivityManager Class (a custom class to handle network activities, Which is not a subclass of UIViewController or UIView).

    After searching the web I found out that MBProgressHUD is used for the same purpose, but I wasn't able to find out an example on how would I use it globally. (By saying global I mean a singleton object of MBProgressHUD and class methods to SHOW and HIDE it.)

    Following is what I have tried yet, but, failed: In AppDelegate.h:

    @property (nonatomic, retain) MBProgressHUD *hud;

    In AppDelegate.m:

    @synthesize hud;

    In some random UIViewController object:

    appDelegate.hud = [MBProgressHUD showHUDAddedTo:appDelegate.navigationController.topViewController.view animated:YES];
    appDelegate.hud.labelText = @"This will take some time.";
    

    And while hiding it, from NetworkActivityManager Class:

    [MBProgressHUD hideHUDForView:appDelegate.navigationController.topViewController.view animated:YES];
    

    This makes the project to crash after some time (due to memory issues.) I am using ARC in my project and also, I am using the ARC version of MBProgressHUD.

    Am I missing something?

    Important Question:

    Can I make MBProgressHUD work like UIAlertView? (Saying that I mean implementation of MBProgressHUD independent of UIView -- sa it uses showHUDAddedTo: to present itself) ???

    Please Note: In the above code of hiding MBProgressHUD, View may be changed from what it was when showing MBProgressHUD.

    Any Help greatly appreciated.

  • viral
    viral over 11 years
    How would I call it to show from the class which is not UIView or UIViewController subclass. This is the reason why I want to make it independent of UIViews. Like UIAlertView, any idea on this ???
  • viral
    viral over 11 years
    Any class which represent MODEL of the project, not VIEWS or CONTROLLERS.
  • viral
    viral over 11 years
    what would be view in [MBProgressHUD showHUDAddedTo:view animated:YES];
  • Matej Bukovinski
    Matej Bukovinski over 11 years
    Which is a good thing. In theory you could do something like this to have a constant reference to it, but that will cause all kinds of trouble if you call show: before before hide: is completely done animating out, so I would strongly recommend that you don't do that.
  • Khawar
    Khawar over 10 years
    If using this way, the progress HUD does not rotate with device orientation. Anyone got solution?
  • David Lawson
    David Lawson over 10 years
    This worked a lot better for me: UIWindow *window = [[UIApplication sharedApplication] delegate].window, and it solves the rotation problem
  • septerr
    septerr over 10 years
    Don't mention AppDelegate...it might scare people away before they even read your answer.
  • ManiaChamp
    ManiaChamp over 9 years
    It will not work when your application is in Landscape mode only. It shows the hud in vertical alignment. I am facing the same issue.
  • Ravi Ojha
    Ravi Ojha over 8 years
    Its working , but i am facing a problem when i poptoviewcontroller the indicator showing on the left bar button.
  • viral
    viral almost 8 years
    Thanks for the answer, I ended up using "SVProgressHUD" instead of this this one. :)
  • pkc456
    pkc456 almost 7 years
    I follow this approach, but it results in flickering when trying to add multiple(more than 10) HUD at a time. To avoid flickering and to add only one HUD at a time, see this answer.
  • Yao Li
    Yao Li over 6 years
    agree, SVProgressHUD is so easy to use.
  • Dharmik
    Dharmik almost 4 years
    It is not fully customisable like MBProgressHud. I tried to clear background blur part, I want it transparent but not possible as far as I know. Still MBProgressHud is better for now..