web-dev-qa-db-fra.com

Utilisation de MBProgressHUD Globally + make singleton

Dans mon projet, chacun des événements d'interaction utilisateur effectue un appel réseau (ce qui est TCP, pas HTTP). J'ai besoin d'un indicateur d'activité global pour show à partir d'une classe UIViewController et hide from NetworkActivityManager aléatoire (une classe personnalisée permettant de gérer les activités réseau, qui n'est pas une sous-classe d'UIViewController ou UIView).

Après une recherche sur le Web, j'ai découvert que MBProgressHUD est utilisé dans le même but, mais je n'ai pas été en mesure de trouver un exemple de la manière dont je l'utiliserais globalement. (Par global, je veux dire un objet singleton de MBProgressHUD et des méthodes de classe pour le MONTRER et le CACHER.)

Voici ce que j’ai encore essayé, mais échoué: Dans AppDelegate.h:

@property (nonatomic, retain) MBProgressHUD *hud;

Dans AppDelegate.m:

@synthesize hud;

Dans certains objets UIViewController aléatoires:

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

Et tout en le cachant, de NetworkActivityManager Classe:

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

Cela provoque le blocage du projet après un certain temps (en raison de problèmes de mémoire.) J'utilise ARC dans mon projet et j'utilise également la version ARC de MBProgressHUD .

Est-ce que je manque quelque chose?

Question importante:

Puis-je faire en sorte que MBProgressHUD fonctionne comme UIAlertView? (En disant que je veux dire implémentation de MBProgressHUD indépendant de UIView - sa utilise showHUDAddedTo: pour se présenter) ???

Remarque: dans le code de masquage de MBProgressHUD ci-dessus, l'affichage peut être modifié par rapport à ce qu'il était lors de l'affichage de MBProgressHUD.

Toute aide grandement appréciée.

23
viral

Vous pouvez ajouter ceci à une classe de votre choix:

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

Cela peut être que appelé sur n'importe quelle classe. Vous n'avez pas besoin de garder une référence forte au HUD lorsque vous utilisez ces méthodes pratiques de classe.

En fonction de votre situation spécifique, vous souhaiterez probablement également traiter les cas dans lesquels un nouveau hud est demandé avant que l'autre ne soit masqué. Vous pouvez manger le hud précédent quand un nouveau arrive ou venir avec une sorte de file d'attente, etc.

Masquer l'instance de HUD précédente avant d'en afficher une nouvelle est assez simple.

+ (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
Matej Bukovinski

REMARQUE...

comme avec beaucoup de problèmes iOS, ceci est maintenant complètement désuet.

Ces jours-ci, vous n'utilisez certainement qu'un trivial

Vue conteneur

pour tout problème comme celui-ci.

Tutoriel complet sur les conteneurs pour débutants .. tutorial!

MBProgressHUD était une solution miraculeuse dans la journée, car il y avait un "trou drastique" dans le pipeline d'Apple.

Mais (comme beaucoup de choses merveilleuses du passé), ce n’est que l’histoire maintenant. Ne fais rien comme ça aujourd'hui.


Juste FWIW, 2014, voici une configuration très simple que nous utilisons. Par David Lawson ...

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

comme dit Matej, utilisez simplement 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 = @"";
}

Définissez les titres dans votre code où vous les utilisez - car vous les modifiez très souvent lors d'une exécution. ("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];
    }];
}

Changez Huddle pour prendre les textes comme argument si vous le souhaitez

Vous voulez toujours self.hud.minShowTime = 0.1; pour éviter le scintillement

Presque toujours self.hud.dimBackground = YES; qui bloque également l'interface utilisateur

Conceptuellement bien sûr vous devez généralement "attendre un peu" pour commencer/terminer le travail lorsque vous lancez un tel processus, comme pour toute programmation similaire avec l'interface utilisateur.

Donc, dans la pratique, le code ressemblera généralement à ceci ...

-(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                                                  \
            )

C'est tout l'histoire maintenant :) https://stackoverflow.com/a/23403979/294884

7
Fattie

Cette réponse est ce que j'utilise depuis 5-6 applications maintenant, car elle fonctionne également parfaitement à l'intérieur de blocs. Cependant, j'ai trouvé un problème avec cela. Je peux le faire apparaître, mais je ne peux pas le faire disparaître si UIAlertView est également présent. Si vous regardez l'implémentation, vous pouvez voir pourquoi. Changez-le simplement en ceci:

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

Cela garantira que vous retirez le HUD des mêmes fenêtres que celles affichées.

3
Zoltan Varadi

J'ai trouvé la réponse de @Matej Bukovinski très utile, car je viens juste de commencer à utiliser Swift et, dans le but d'utiliser ses méthodes, de définir une police globale pour MBProgressHUD. J'ai converti le code en Swift et je souhaite partager le code ci-dessous:

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

Le code ci-dessus est placé dans un fichier global où je conserve toutes mes aides et constantes globales.

2
Michael Shang

Note : Vu les points de vue exprimés par cette Question, j'ai décidé d'afficher la solution que j'ai choisie. Ce n'est pas une réponse à ma question. (par conséquent, la réponse acceptée reste acceptée)

A cette époque, j'ai utilisé SVProgressHUD car il était très simple à intégrer et à utiliser.

Il vous suffit de faire glisser le dossier SVProgressHUD/SVProgressHUD dans votre projet. (Vous pouvez également choisir les cocoapodes OR carthage)


En Objective-C:

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

Dans Swift:

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

En outre, Afficher et masquer le HUD doit être exécuté sur le fil principal . (Plus précisément, vous en aurez besoin pour cacher le HUD dans une fermeture en arrière-plan)

exemple:

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

Il existe d'autres méthodes pour afficher des messages personnalisés avec le HUD, indiquant les succès/échecs pour une courte durée et la suppression automatique.

MBProgressHUD reste un bon choix pour les développeurs. C'est juste que j'ai trouvé SVProgressHUD pour répondre à mes besoins.

1
viral

Je l'ai utilisé comme ci-dessous .. J'espère que cela vous aide ..

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

De vues aléatoires: -

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

1
Maulik

J'utilisais le code de @Michael Shang et avais toutes sortes de comportements incohérents avec l'affichage des HUD. Il s'avère que l'utilisation de la dernière fenêtre n'est pas fiable car le clavier iOS peut simplement le masquer. Donc, dans la majorité des cas, vous devriez avoir la fenêtre en utilisant le AppDelegate comme mentionné par @David Lawson.

Voici comment dans Swift:

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

Cependant, avec ce qui précède, votre HUD apparaîtra derrière le clavier iOS (s’ils se chevauchent). Si vous avez besoin que votre HUD recouvre le clavier, utilisez la méthode de la dernière fenêtre.

Dans mon cas, ce qui se passait est que je montre au HUD puis appelle resignFirstResponder() tout en cachant la fenêtre à laquelle le HUD a été ajouté. C’est donc quelque chose à prendre en compte, la seule fenêtre qu’il est garanti de conserver est la première.

J'ai fini par créer une méthode qui pourrait éventuellement ajouter le HUD au-dessus du clavier si nécessaire:

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

Ajoutez ces deux méthodes pour afficher ou masquer le chargeur dans votre classe singleton

- (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

Pour afficher une MBProgressHUD à la fois, vous pouvez vérifier si le HUD a déjà été ajouté dans la même vue ou non. Si ce n'est pas le cas, ajoutez le HUD, sinon ne ajoutez pas de nouveau 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