Разработка iPhone/iPod touch приложений: Использования индикатора загрузки UIActivityIndicatorView.

Очень многим приложениям требуется загружать данные с удаленного сервера или использовать операции, которые занимают много времени. В таком случае пользователю нужно сообщать о длительных операциях и ставить индикатор загрузки. Это можно сделать с помощью визуального компонентаUIActivityIndicatorView. В этой статье я покажу несколько примеров его использования.

Для наглядности будет создано приложение с несколькими кнопками, каждая из которых будет показывать свой вариант использования индикатора загрузки UIActivityIndicatorView.

Я создал View-Based Application и назвал его Activity. Весь код, который будет описан ниже находиться в файлах ActivityViewController.h или ActivityViewController.m.

Первое что нужно описать это загрузка приложения и получения данных от сервера. В большинстве случаев первое, что видит пользователь, это Splash Screen. На нем нельзя размещать компоненты, это просто изображение. Но когда приложение уже загрузило свои компоненты, можно добавить индикатор загрузки и сделать подключение к серверу. Для того, что бы приложение показало Splash Screen, нужно положить в ресурсы файл Default.png.

Splash Screen

Splash Screen

Мы можем сделать UIView с таким же фоном как Splash, добавить к нему индикатор загрузки и спокойно работать с сервером. Выглядеть это будет хорошо и для пользователя понятно. В Interface Builder этот UIView имеет такую структуру:

Структура первого UIView после Splash Screen

Структура первого UIView после Splash Screen

Установим этот UIView как главный UIView нашего контроллера и первое что увидит пользователь после Splash Screen будет индикатор загрузки с пояснением что происходит. Для того что бы показать Splash Screen подольше, можно продлить процесс загрузки компонентов из nib файла. Для этого в методе viewDidLoad пишем следующий код:


- (void)viewDidLoad {
    [super viewDidLoad];
    [NSThread sleepForTimeInterval:2];
    [self performSelector:@selector(showAppView:) withObject:nil afterDelay:2.0f];
}

Где sleepForTimeInterval продлевает загрузку компонентов на 2 секунды, тем самым Splash виден на 2 секунды дольше. А в функции showAppView покажет нужный UIView с кнопками. Итак, окно с индикатором после показа Splash Screen будет выглядеть так:

Загрузка приложения

Загрузка приложения

Итак, переходим к нашему главному View. В контроллере нужно объявить главный UIView приложения, у меня это свойство appView, а также обработчики нажатия для 5 кнопок. В .h файле это будет выглядеть так:


@interface ActivityViewController : UIViewController <UIActionSheetDelegate> {
    IBOutlet UIView *appView;
}

@property (nonatomic, retain) UIView *appView;

-(IBAction) onFirstButtonClick:(id)sender;
-(IBAction) onSecondButtonClick:(id)sender;
-(IBAction) onThirdButtonClick:(id)sender;
-(IBAction) onFourthButtonClick:(id)sender;
-(IBAction) onFifthButtonClick:(id)sender;

@end

и Connection Inspector в Interface Builder

Главный UIView приложения

Главный UIView приложения

Все подготовлено, теперь можно переходить к написанию основного кода.

Первый пример с использованием UIActionSheet.

Основным требованиям при операциях является блокировка любых действий пользователя. Первый пример использования будет основан на UIActionSheet. В таком случае нам нужно имплементировать  <UIActionSheetDelegate> в наш контроллер. Это поможет нам обрабатывать события нажатия на кнопки (если такие добавить). Мы же будем его использовать в самом простом варианте, добавим текст, сообщающий пользователю что происходит и индикатор с анимацией загрузки. Что бы показать такой индикатор нужно создать UIActivityIndicatorView, и добавить его в UIActionSheet. Пример как это сделать приведен ниже.


-(IBAction) onFirstButtonClick:(id)sender{
    UIActivityIndicatorView *progressView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(-12.4, -10, 25, 25)];
    progressView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
    progressView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin |
                                     UIViewAutoresizingFlexibleRightMargin |
                                     UIViewAutoresizingFlexibleTopMargin |
                                     UIViewAutoresizingFlexibleBottomMargin);

    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"First activity example"
                                                      delegate:self
                                             cancelButtonTitle:nil
                                        destructiveButtonTitle:nil
                                             otherButtonTitles:nil
                           ];

    [actionSheet addSubview:progressView];
    [actionSheet showInView:self.view];
    [actionSheet setBounds:CGRectMake(0,0,320, 100)];
    [progressView startAnimating];

    [self performSelector:@selector(showFirstActivity:) withObject:actionSheet afterDelay:0.1f];
    [progressView release];
}

-(void) showFirstActivity:(id)sender{
    [NSThread sleepForTimeInterval:2];
    UIActionSheet *actionSheet = (UIActionSheet *)sender;
    [actionSheet dismissWithClickedButtonIndex:0 animated:YES];
    [actionSheet release];
}

Как видно из примера мы не добавили ни одной кнопки. Если это сделать, то для обработки нажатия потребуется более сложный вызов метода showFirstActivity. Думаю для программиста разобраться в первых строчках не составит труда. Немного поясню что мы сделали в последних строчках. При вызове метода showFirstActivity без задержки мы не получим анимацию UIActivityIndicatorView. Поэтому приложению нужно давать немного времени и вызывать этот метод с задержкой.

И вот что мы увидим на экране в результате:

Использование UIActionSheet

Использование UIActionSheet

При таком подходе нам не нужно беспокоиться о том, что пользователь будет дальше генерировать события. UIActionSheet блокирует все нажатия до вызова у него метода dismissWithClickedButtonIndex.

Второй пример с использованием UIAlertView.

В UIAlertView можно добавлять subView. Такую возможность можно использовать для отображения индикатора. Для этого нам нужно создать UIAlertView без кнопок и добавить в него UIActivityIndicatorView. Для этого можно использовать метод addSubView.


-(IBAction) onSecondButtonClick:(id)sender{
    UIAlertView *progressAlert = [[UIAlertView alloc] initWithTitle: @"Second activity example"
                                               message: @"Please wait..."
                                              delegate: self
                                     cancelButtonTitle: nil
                                     otherButtonTitles: nil];

    UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
    activityView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
    activityView.frame = CGRectMake(139.0f-18.0f, 80.0f, 37.0f, 37.0f);
    [progressAlert addSubview:activityView];
    [activityView startAnimating];
    [self performSelector:@selector(hideAlert:) withObject:progressAlert afterDelay:2.1f];
    [progressAlert show];
    [progressAlert release];
}

-(void) hideAlert:(id)sender{
    [(UIAlertView *)sender dismissWithClickedButtonIndex:0 animated:YES];
}

Убрать UIAlertView можно вызвав у него метод dismissWithClickedButtonIndex. На экране это будет так:

Использование UIAlertView

Использование UIAlertView

Третий пример – использования полупрозрачный UIView

Для этого нам нужно к основному view добавить полупрозрачный UIView с размерами экрана. В этот UIView можно положить UIActivityIndicatorView.


-(IBAction) onThirdButtonClick:(id)sender{
    UIView *thirdView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
    UIColor *color = [[UIColor alloc] initWithWhite:0.5f alpha:0.5f];
    [thirdView setBackgroundColor:color];
    [color release];

    UIActivityIndicatorView *progressView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(145, 215, 25, 25)];
    progressView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
    progressView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin |
                                     UIViewAutoresizingFlexibleRightMargin |
                                     UIViewAutoresizingFlexibleTopMargin |
                                     UIViewAutoresizingFlexibleBottomMargin);
    [progressView startAnimating];
    [thirdView addSubview:progressView];
    [self.view addSubview:thirdView];

    [progressView release];
    [self performSelector:@selector(hideThirdView:) withObject:thirdView afterDelay:2.1f];
}

-(void) hideThirdView:(id)sender{
    UIView *thirdView = (UIView *)sender;
    [thirdView removeFromSuperview];
    [thirdView release];
}

После завершения работы нужно убрать этот UIView с экрана методом removeFromSuperview.

Полупрозрачный UIView

Полупрозрачный UIView

Четвертый пример. Блокировка нажатий

Можно размещать UIActivityIndicatorView в любом месте на экране, но сделать блокировку нажатий. Об этом уже писал Павел Тайкало в статье Разработка iPhone/iPod touch приложений: Отключение touch событий. Код наведен ниже:


-(IBAction) onFourthButtonClick:(id)sender{
    [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
    UIActivityIndicatorView *progressView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(145, 285, 25, 25)];
    progressView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
    progressView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin |
                                     UIViewAutoresizingFlexibleRightMargin |
                                     UIViewAutoresizingFlexibleTopMargin |
                                     UIViewAutoresizingFlexibleBottomMargin);
    [self.view addSubview:progressView];
    [progressView startAnimating];
    [self performSelector:@selector(hideFourthView:) withObject:progressView afterDelay:2.1f];
}

-(void) hideFourthView:(id)sender{
    UIActivityIndicatorView *progressView = (UIActivityIndicatorView *)sender;
    [progressView removeFromSuperview];
    [progressView release];
    [[UIApplication sharedApplication] endIgnoringInteractionEvents];
}

В этом примере строкой  [[UIApplication sharedApplication] beginIgnoringInteractionEvents] мы отключаем реакцию на нажатия и после завершения нужного действия, снова включаем [[UIApplication sharedApplication] endIgnoringInteractionEvents];

Блокировка нажатий

Блокировка нажатий

Последний метод

Этот метод не документирован. Для его использования нужно добавить описания UIProgressHUD в ActivityViewController.h.


@interface UIProgressHUD : NSObject
- (UIProgressHUD *) initWithWindow: (UIView*)aWindow;
- (void) show: (BOOL)aShow;
- (void) setText: (NSString*)aText;
@end

И методы обработки:


-(IBAction) onFifthButtonClick:(id)sender{
    [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
    id alert = [[UIProgressHUD alloc] initWithWindow:[self.view superview]];
    [alert setText:@"Please wait."];
    [alert show:YES];
    [self performSelector:@selector(hideFifthView:) withObject:alert afterDelay:2.0];
}

- (void) hideFifthView: (id)sender
{
    [sender show:NO];
    [sender release];
    [[UIApplication sharedApplication] endIgnoringInteractionEvents];
}

Получим такое изображение.

UIProgressHUD

UIProgressHUD

Очень похоже на стандартные компоненты, такие как изменение громкости.

На практике можно использовать любой из этих методов. Добавить такие компоненты можно из кода и легко ими управлять. Надеюсь информация была для вас полезной.

Не заставляйте своих пользователей долго ждать :).

 

Комментарии

[...] уже говорилось, в статье об индикаторах загрузки, это самый момент подменить Splash Screen, если приложение [...]

Оставить комментарий