全局使用MBProgressHUD +使其成为单身人士

时间:2012-08-20 06:25:04

标签: iphone ios singleton mbprogresshud

在我的项目中,每个用户交互事件都进行网络调用(即TCP,而不是HTTP)。我需要将活动指标从全局变为显示来自UIViewController 隐藏来自NetworkActivityManager类(用于处理网络活动的自定义类,其中不是UIViewController或UIView的子类。

搜索网页后,我发现 MBProgressHUD 用于同一目的,但我无法找到一个关于如何全局使用它的示例。 (通过说全局我的意思是 MBProgressHUD 的单个对象以及显示和隐藏它的类方法。)

以下是我尝试过的,但是,失败了: 在 AppDelegate.h:

@property (nonatomic, retain) MBProgressHUD *hud;

AppDelegate.m中:

@synthesize hud;

在一些随机的UIViewController对象中:

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

在隐藏它的同时,从NetworkActivityManager Class:

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

这会使项目在一段时间后崩溃(由于内存问题。) 我在我的项目中使用ARC,而且,我正在使用ARC版本的 MBProgressHUD

我错过了什么吗?

重要问题:

我可以让 MBProgressHUD 像UIAlertView一样工作吗? (说我的意思是 MBProgressHUD 的实现独立于UIView - 它使用showHUDAddedTo:来呈现自己)???

请注意:在上面隐藏MBProgressHUD的代码中,View可能会与显示MBProgressHUD时的内容有所不同。

非常感谢任何帮助。

9 个答案:

答案 0 :(得分:66)

您可以将此添加到您喜欢的课程中:

+ (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];
}

这可以在任何课程上调用。使用这些类方便方法时,您无需对HUD进行强有力的引用。

根据您的具体情况,您可能还希望处理在隐藏另一个hud之前请求新hud的情况。当新的进入或者出现某种排队等时,你可以躲起以前的hud。

在显示新的HUD实例之前隐藏它是非常简单的。

+ (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;
}

答案 1 :(得分:7)

注意...

与许多iOS问题一样,现在已经完全过时了。

这些天你当然只是使用了一个微不足道的

容器视图

对于这样的任何问题。

初学者的完整容器视图教程.. tutorial!

MBProgressHUD是当天的一个奇迹般的解决方案,因为它有一个很大的漏洞"在Apple的管道中。

但是(和过去许多精彩的东西一样),现在只是历史。今天不要这样做。


Just FWIW,2014,这是我们使用的一个非常简单的设置。 Per David Lawson ......

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

正如Matej所说,只需使用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 = @"";
}

在您使用它的代码中设置标题 - 因为您经常在运行期间更改。 ("步骤1" ......"步骤2"等)

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

如果您愿意,可以通过改变会话来将文本作为参数

您总是希望 self.hud.minShowTime = 0.1; 以避免闪烁

几乎总是 self.hud.dimBackground = YES; 也阻止了用户界面

从概念上讲,当然你通常需要等待"稍微等待"当你启动这样一个过程时,开始工作/结束工作,就像使用UI进行任何类似的编程一样。

所以在实践中代码通常看起来像这样......

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

方便的宏..

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

现在这都是历史了:) https://stackoverflow.com/a/23403979/294884

答案 2 :(得分:3)

This回答是我现在用于5-6应用程序的答案,因为它在块内也能完美运行。但是我发现它有问题。我可以让它显示,但如果UIAlertView也存在,它不会消失。如果你看看实现,你可以看到原因。只需将其更改为:

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

这将确保您从显示的相同窗口中移除HUD。

答案 3 :(得分:2)

我发现@Matej Bukovinski的回答非常有帮助,因为我刚刚开始使用Swift,我使用他的方法的目的是为MBProgressHUD设置一个全局字体,我已经将代码转换为swift并愿意分享以下代码:

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

上面的代码放在一个全局文件中,我保留了所有的全局帮助器和常量。

答案 4 :(得分:1)

我用过它如下..希望它可以帮助你......

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

来自随机视图: -

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

答案 5 :(得分:1)

注意:考虑到这个问题的观点,我决定发布我选择作为解决方案的方式。 这不是我的问题的答案。(因此,接受的答案仍然被接受)

当时我最终使用SVProgressHUD,因为它非常易于集成和使用。

您只需将SVProgressHUD / SVProgressHUD文件夹拖到项目中即可。 (你可以选择去cocoapods或迦太基)

在Objective-C中:

[SVProgressHUD show]; // Show
[SVProgressHUD dismiss]; // Dismiss

在Swift中:

SVProgressHUD.show() // Show
SVProgressHUD.dismiss() // Dismiss

此外,显示和隐藏HUD需要在主线程上执行。 (具体来说,你需要这个来隐藏背景中某些闭包的HUD)

<强> e.g:

dispatch_async(dispatch_get_main_queue(), ^{
    [SVProgressHUD dismiss]; // OR SHOW, whatever the need is.
});

还有其他方法可以显示带有HUD的自定义消息,显示短时间内的成功/失败以及自动关闭。

MBProgressHUD 仍然是开发人员的不错选择。只是我找到 SVProgressHUD 来满足我的需求。

答案 6 :(得分:0)

添加这两种方法以在单件类中显示或隐藏加载器

- (void)startLoaderWithText:(NSString *)title View:(UIView *)view{
    progressHud = [MBProgressHUD showHUDAddedTo:view animated:YES];
    progressHud.labelText = title;
    progressHud.activityIndicatorColor = [UIColor grayColor];
    progressHud.color = [UIColor clearColor];
    [progressHud show:YES];
}

- (void)stopLoader{
    [progressHud hide:YES];
}

答案 7 :(得分:0)

我使用的是@Michael Shang的代码,并且在显示HUD时出现各种不一致的行为。原来使用最后一个窗口是不可靠的,因为iOS键盘可能只是隐藏它。所以在大多数情况下,你应该使用@David Lawson提到的AppDelegate来获取窗口。

以下是Swift中的内容:

let window = UIApplication.sharedApplication().delegate!.window!!
let hud = MBProgressHUD.showHUDAddedTo(window, animated: true)

然而,有了上述内容,您的HUD将显示在iOS键盘后面(如果它们重叠)。如果您需要HUD覆盖键盘,请使用最后一个窗口方法。

在我的情况下,发生的事情是我会显示HUD,然后立即调用resignFirstResponder()隐藏添加HUD的窗口。所以这是需要注意的事项,唯一可以保留的窗口是第一个。

我最终创建了一个方法,如果需要,可以选择在键盘上方添加HUD:

func createHUD(size: CGSize, overKeyboard: Bool = false) -> MBProgressHUD {
    let window = overKeyboard ? UIApplication.sharedApplication().windows.last!
                              : UIApplication.sharedApplication().delegate!.window!!
    let hud = MBProgressHUD.showHUDAddedTo(window, animated: true)
    hud.minSize = size
    hud.bezelView.style = .SolidColor
    hud.bezelView.color = UIColor(white: 0, alpha: 0.8)
    return hud
}

答案 8 :(得分:0)

要一次显示一个MBProgressHUD,您可以检查天气HUD是否已添加到同一视图中。如果没有,则添加HUD,否则不添加新的HUD。

-(void)showLoader{    
    dispatch_async(dispatch_get_main_queue(), ^{
        BOOL isHudAlreadyAdded = false;

        UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
        NSEnumerator *subviewsEnum = [window.subviews reverseObjectEnumerator];
        for (UIView *subview in subviewsEnum) {
            if ([subview isKindOfClass:[MBProgressHUD class]]) {
                isHudAlreadyAdded = true;
            }
        }
        if(isHudAlreadyAdded == false){
            [MBProgressHUD showHUDAddedTo:window animated:YES];
        }
    });
}

-(void)hideLoader{
    dispatch_async(dispatch_get_main_queue(), ^{
        UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
        [MBProgressHUD hideHUDForView:window animated:YES];
    });
}