web-dev-qa-db-ja.com

MBProgressHUDをグローバルに使用+シングルトンにする

私のプロジェクトでは、各ユーザーインタラクションイベントがネットワーク呼び出しを行います(これはTCPであり、HTTPではありません)。アクティビティインジケーターをグローバルにする必要がありますshow from a random UIViewController and hide from NetworkActivityManager Class(ネットワークアクティビティを処理するカスタムクラス、これはUIViewControllerまたはUIViewのサブクラスではありません)。

Webを検索したところ、MBProgressHUDが同じ目的で使用されていることがわかりましたが、グローバルに使用する方法の例を見つけることができませんでした。 (グローバルとは、MBProgressHUDのシングルトンオブジェクトと、それを表示および非表示にするクラスメソッドを意味します。)

以下は私がまだ試したものですが、失敗しました:In 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を使用しています。また、ARCバージョンのMBProgressHUDを使用しています。

私は何かが足りないのですか?

重要な質問:

MBProgressHUDをUIAlertViewのように機能させることはできますか? (つまり、UIViewから独立したMBProgressHUDの実装を意味します--saそれはshowHUDAddedTo:を使用してそれ自体を提示します)???

注意:MBProgressHUDを非表示にする上記のコードでは、ビューがMBProgressHUDを表示したときのビューから変更される場合があります。

どんな助けでも大歓迎です。

23
viral

あなたはこれをあなたの好みのクラスに加えることができます:

+ (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インスタンスを非表示にするのは、非常に簡単です。

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

注意...

多くのiOSの問題と同様に、これは今では劇的に、完全に時代遅れになっています。

最近は確かに些細なことを使うだけです

コンテナビュー

このような問題のために。

初心者向けの完全なコンテナビューチュートリアル.. チュートリアル!

MBProgressHUDは、Appleのパイプラインに「劇的な穴」があったため、当時は奇跡的なソリューションでした。

しかし(過去の多くの素晴らしいものと同様に)、これは今の歴史に過ぎません。今日はこのようなことをしないでください。


ちょうど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をブロックします

概念的にはもちろん通常、このようなプロセスを起動するときは、作業を開始/終了するために「少し待つ」必要があります。 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

8
Fattie

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
Zoltan Varadi

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

上記のコードは、すべてのグローバルヘルパーと定数を保持するグローバルファイルに配置されます。

2
Michael Shang

:この質問の見解を考慮して、解決策として選択した方法を投稿することにしました。 これは私の質問に対する答えではありません。(したがって、受け入れられた回答は受け入れられたままです)

その時、統合と使用が非常に簡単だったので、結局 SVProgressHUD を使用しました。

SVProgressHUD/SVProgressHUDフォルダーをプロジェクトにドラッグするだけです。 (ココアポッドを選ぶこともできますORカルタゴも)


Objective-Cの場合:

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

Swiftの場合:

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が私のニーズに合っていることがわかっただけです。

1
viral

私はそれを以下のように使用しました..それがあなたを助けることを願っています..

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

1
Maulik

私は@MichaelShangのコードを使用していて、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
}
_
0
Code Baller

これらの2つのメソッドを追加して、シングルトンクラスでローダーを表示または非表示にします

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

一度に1つの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];
    });
}
0
pkc456