Подтвердить что ты не робот

Использование MBProgressHUD Globally + делает его singleton

В моем проекте каждое из событий взаимодействия с пользователем создает сетевой вызов (который является TCP, а не HTTP). Мне нужно, чтобы индикатор активности был глобальным до показывать из случайного UIViewController и скрывать из NetworkActivityManager класса (пользовательский класс для обработки сетевых действий, который не является подклассом UIViewController или UIView).

После поиска в Интернете я обнаружил, что MBProgressHUD используется для этой же цели, но я не смог найти пример того, как использовать его во всем мире. (Говоря глобальным, я имею в виду одноэлементный объект MBProgressHUD и методы класса для SHOW и HIDE.)

Вот что я пробовал еще, но, не удалось: В 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? (Говоря, что я имею в виду реализацию MBProgressHUD, не зависящей от UIView - sa, она использует showHUDAddedTo: для представления себя).

Обратите внимание: в приведенном выше коде скрытия MBProgressHUD View может быть изменен с того, что было при показе MBProgressHUD.

Любая помощь была высоко оценена.

4b9b3361

Ответ 1

Вы можете добавить это в класс по своему вкусу:

+ (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 перед показом нового довольно просто.

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

Ответ 2

Примечание...

как и во многих проблемах iOS, теперь это резко, совершенно устарело.

В эти дни вы, конечно, просто используете тривиальный

Вид контейнера

для любой проблемы, подобной этой.

Полный учебник для просмотра контейнеров для начинающих. учебник!

MBProgressHUD было чудесным решением в тот же день, потому что в конвейере Apple была "резкая дыра".

Но (как и во многих замечательных вещах из прошлого), это только история. Сегодня не делайте ничего подобного.


Просто FWIW, 2014, здесь очень простая настройка, которую мы используем. Пер Дэвид Лоусон...

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

как говорит Матей, просто используйте 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;, который также блокирует пользовательский интерфейс

Концептуально, конечно, вам обычно приходится "немного ждать", чтобы начать работу/завершение работы, когда вы вызываете такой процесс, как при любом аналогичном программировании с пользовательским интерфейсом.

Таким образом, на практике код обычно будет выглядеть так...

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

Теперь это история. fooobar.com/questions/3297/...

Ответ 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 из тех же окон, что и на нем.

Ответ 4

Я нашел @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)
}

Вышеприведенный код помещается в глобальный файл, где я сохраняю все свои глобальные помощники и константы.

Ответ 5

Я использовал его, как показано ниже. Надеюсь, вам это поможет.

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

Из случайных представлений: -

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

Ответ 6

Примечание. Учитывая взгляды, которые этот вопрос получает, я решил опубликовать способ, который я выбрал в качестве решения. Это НЕ ответ на мой вопрос. (Следовательно, принятый ответ остается принятым)

В то время я закончил использование SVProgressHUD, так как было очень просто интегрировать и использовать.

Все, что вам нужно сделать, это просто перетащить папку SVProgressHUD/SVProgressHUD в свой проект. (Вы также можете выбрать для коко-каподов ИЛИ carthage)


В Objective-C:

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

В Swift:

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

Кроме того, Show и hide HUD необходимо выполнить в основном потоке. (В частности, вам понадобится это, чтобы скрыть HUD в некотором закрытии в фоновом режиме)

например:.

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

Существуют дополнительные методы отображения пользовательских сообщений с HUD, показывающие успех/сбой в течение короткой продолжительности и автоматическое отключение.

MBProgressHUD по-прежнему остается хорошим выбором для разработчиков. Просто я нашел SVProgressHUD в соответствии с моими потребностями.

Ответ 7

Добавьте эти два метода, чтобы показать или скрыть загрузчик в вашем одиночном классе

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

Ответ 8

Я использовал код от @Michael Shang и имел все виды непоследовательного поведения с показом HUD. Оказывается, последнее окно ненадежно, так как клавиатура iOS может просто скрыть ее. Поэтому в большинстве случаев вы должны получить окно с помощью AppDelegate, как указано @David Lawson.

Здесь, как в 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
}

Ответ 9

Чтобы показать один 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];
    });
}