25

在我的项目中,每个用户交互事件都会进行一次网络调用(这是 TCP,而不是 HTTP)。我需要 Activity Indicator 是全局的,以便随机显示UIViewController隐藏Class(处理网络活动的自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类:

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

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

我错过了什么吗?

重要问题:

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

请注意:在上述隐藏 MBProgressHUD 的代码中,显示 MBProgressHUD 时的 View 可能会发生变化。

非常感谢任何帮助。

4

9 回答 9

67

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

+ (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 实例之前隐藏之前的 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;
}
于 2012-08-22T11:40:17.350 回答
8

笔记...

与许多 iOS 问题一样,这现在已经彻底过时了。

这些天你肯定只是用一个微不足道的

容器视图

对于这样的任何问题。

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

MBProgressHUD 在当时是一个神奇的解决方案,因为苹果的管道中有一个“巨大的漏洞”。

但是(就像过去的许多美好事物一样),现在这只是历史。今天不要做这样的事。


只是 FWIW,2014,这是我们使用的一个非常简单的设置。根据大卫劳森...

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

如果您愿意,可以更改 huddle 以将文本作为参数

你总是想要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

于 2014-04-14T09:04:54.720 回答
3

这个答案是我现在用于 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。

于 2013-06-12T13:22:31.787 回答
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)
}

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

于 2015-08-24T03:15:31.647 回答
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];

于 2012-08-20T06:35:28.377 回答
1

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

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

您只需将 SVProgressHUD/SVProgressHUD 文件夹拖到您的项目中即可。(您也可以选择吃可可足类动物或迦太基)


在 Objective-C 中:

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

在斯威夫特:

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

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

例如:

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

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

MBProgressHUD仍然是开发人员的不错选择。只是我发现SVProgressHUD适合我的需要。

于 2016-06-30T13:52:51.140 回答
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];
    });
}
于 2017-06-28T12:37:51.033 回答
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
}
于 2016-11-27T03:00:50.700 回答
-1

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

- (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];
}
于 2016-06-01T07:28:17.960 回答