Доброе утро/день/вечер/ночь %username%!
В процессе реализации очередного проекта появилась необходимость реализовать эффективное оповещение пользователя о чём-либо (например, об отсутствии интернет соединения). Так как же это сделать? Стандартный класс UIAlertView оказался для этой цели слишком громоздким и скучным, и, не найдя более ничего подходящего, было решено написатьсвоё казино с блекдже… свой класс оповещения.
Итак, приступим. Главным критерием для данного класса стал «вызов одной строчкой кода», соответственно я получил метод:
Исходя из поставленной задачи «очень простого оповещения пользователя» было решено использовать:
Для начало мы возьмём UILabel и «заточим» под свои нужды:
Дальше необходимо узнать – «А сколько же наше сообщение займет места на экране?»
Метод для NSString sizeWithFont:(UIFont *)font constrainedToSize(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode вернет нам в данном случае размеры прямоугольника, в который будет «вписан текст» исходя из условий:
Дальше необходимо из полученных размеров сделать сам прямоугольник с учетом 2х дополнительных размеров:
Всё, на этом пока что мы закончили с UILabel.
Дальше на очереди контейнер для UILabel – первый из двух UIView. Для контейнера необходимо было учесть – цвет фона, граница, отступы от границы. Как дополнение к дизайну «оповещалки» — скругленные углы, тень и прозрачность. Ниже приведен код нашего контейнера
На этом всё. Теперь нам остается задействовать лишь последний оставшийся UIView – rootView. Его мы будем использовать для анимации.
Всё на этом этапе у нас есть подготовленные для дальнейшего использования UILabel с сообщением и 2 UIView контейнера. Осталось только собрать из них матрешку и установить позицию в центре экрана:
В нашем случае анимация была разбита на 3 составляющие:
Bounce-эффект достигался простой анимацией увеличения rootView с размеров с коэффициентом 0.8 до размеров с коэффициентом 1.1 и немедленным уменьшением до естественного размера – коэффициент 1.0. Появление и исчезновение – изменение rootView.alpha с 0.0f до 1.0f и наоборот. Исчезновение так же сопровождается изменением размеров до коэффициента 1.2. Для появления и достижения «пиковой» точки bounce-эффекта (а именно когда будет достигнут коэффициент 1.2) было решено отвести 2/3 общего времени запланированного на анимацию. Остаток времени был использован на переход к нормальному отображению. Дальше пользователю отведено время для возможности прочесть сообщение и в последствии исчезновение сообщения
Начиная с iOS версии 4.0 анимация реализовывается через блоки. Поэтому требуемая версия iOS не ниже 4.0 (в дальнейшем планируется добавить поддержку iOS 3).
метод класса UIView позволяет нам установить:
Код реализации анимации приведен ниже:
Итог
В результате написания данного класса мы получили очень удобную “оповещалку”, которую можно вызвать одной строчкой кода:
![](https://habrastorage.org/r/w1560/storage/037f2ee4/f18b4570/eb7027b9/e552124e.png)
Плюсы данного класса:
Минусы:
Для работы данного класса так же потребуется QuartzCore.framework
Исходный код можно скачать на github, немного дополненный и расширенный
На этом всё. Спасибо за внимание
Предыстория
В процессе реализации очередного проекта появилась необходимость реализовать эффективное оповещение пользователя о чём-либо (например, об отсутствии интернет соединения). Так как же это сделать? Стандартный класс UIAlertView оказался для этой цели слишком громоздким и скучным, и, не найдя более ничего подходящего, было решено написать
Реализация
Итак, приступим. Главным критерием для данного класса стал «вызов одной строчкой кода», соответственно я получил метод:
+ (void) showMessage:(NSString *)message;
Исходя из поставленной задачи «очень простого оповещения пользователя» было решено использовать:
- UILabel — 1шт.
- UIView — 2шт.
Для начало мы возьмём UILabel и «заточим» под свои нужды:
UILabel *messageLabel = [[UILabel alloc] init];
messageLabel.textAlignment = UITextAlignmentCenter;
messageLabel.numberOfLines = 0;
messageLabel.lineBreakMode = UILineBreakModeWordWrap;
messageLabel.text = message;
messageLabel.font = [UIFont fontWithName:@”Helvetica-Bold” size:15.0f];
messageLabel.textColor = [UIColor whiteColor];
messageLabel.backgroundColor = [UIColor clearColor];
Дальше необходимо узнать – «А сколько же наше сообщение займет места на экране?»
CGSize messageSize = [message sizeWithFont:messageLabel.font constrainedToSize:CGSizeMake(160.0f, 9999.0f) lineBreakMode:UILineBreakModeWordWrap];
Метод для NSString sizeWithFont:(UIFont *)font constrainedToSize(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode вернет нам в данном случае размеры прямоугольника, в который будет «вписан текст» исходя из условий:
- многострочность
- ширина блока равна 160.0f (может быть больше, в случае, если слово не умещается в этот размер)
Дальше необходимо из полученных размеров сделать сам прямоугольник с учетом 2х дополнительных размеров:
- Толщина границы родительского элемента (в него мы «положим» UILabel)
- Отступ от границ родительского элемента
CGRect messageRect = CGRectMake(offsetSize.width + borderWidth, offsetSize.height + borderWidth, messageSize.width, messageSize.height);
messageLabel.frame = messageRect;
Всё, на этом пока что мы закончили с UILabel.
Дальше на очереди контейнер для UILabel – первый из двух UIView. Для контейнера необходимо было учесть – цвет фона, граница, отступы от границы. Как дополнение к дизайну «оповещалки» — скругленные углы, тень и прозрачность. Ниже приведен код нашего контейнера
messageSize.width += offsetSize.width*2.0f + borderWidth;
messageSize.height += offsetSize.height*2.0f + borderWidth;
contentRect = CGRectMake(0.0f, 0.0f, messageSize.width, messageSize.height);
UIView *content = [[UIView alloc] init];
content.frame = contentRect;
content.backgroundColor = [UIColor colorWithRed:(60.0f/255.0f) green:(60.0f/255.0f) blue:(60.0f/255.0f) alpha:1.0f];
content.alpha = 0.8f;
content.layer.cornerRadius = 8.0f;
content.layer.shadowRadius = 8.0f;
content.layer.masksToBounds = NO;
content.layer.shadowOffset = CGSizeMake(0.0f, 4.0f);
content.layer.shadowOpacity = 1.0f;
content.layer.borderWidth = 1.0f;
content.layer.borderColor = [[UIColor colorWithRed:(128.0f/255.0f) green:(128.0f/255.0f) blue:(128.0f/255.0f) alpha:1.0f] CGColor];
content.layer.shadowPath = [UIBezierPath bezierPathWithRect:contentRect].CGPath;
На этом всё. Теперь нам остается задействовать лишь последний оставшийся UIView – rootView. Его мы будем использовать для анимации.
UIView *rootView = [[UIView alloc] init];
rootView.tag = 2000;
rootView.frame = contentRect;
rootView.alpha = 0.0f;
Всё на этом этапе у нас есть подготовленные для дальнейшего использования UILabel с сообщением и 2 UIView контейнера. Осталось только собрать из них матрешку и установить позицию в центре экрана:
messageLabel.center = CGPointMake(contentRect.size.width/2.0f, contentRect.size.height/2.0f);
[content addSubview:messageLabel];
[messageLabel release];
[rootView addSubview:content];
[content release];
rootView.center = [[UIApplication sharedApplication] keyWindow].center;
Анимация
В нашем случае анимация была разбита на 3 составляющие:
- Появление
- Имитация bounce-эффекта
- Исчезнование
Bounce-эффект достигался простой анимацией увеличения rootView с размеров с коэффициентом 0.8 до размеров с коэффициентом 1.1 и немедленным уменьшением до естественного размера – коэффициент 1.0. Появление и исчезновение – изменение rootView.alpha с 0.0f до 1.0f и наоборот. Исчезновение так же сопровождается изменением размеров до коэффициента 1.2. Для появления и достижения «пиковой» точки bounce-эффекта (а именно когда будет достигнут коэффициент 1.2) было решено отвести 2/3 общего времени запланированного на анимацию. Остаток времени был использован на переход к нормальному отображению. Дальше пользователю отведено время для возможности прочесть сообщение и в последствии исчезновение сообщения
Начиная с iOS версии 4.0 анимация реализовывается через блоки. Поэтому требуемая версия iOS не ниже 4.0 (в дальнейшем планируется добавить поддержку iOS 3).
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
метод класса UIView позволяет нам установить:
- продолжительность анимации
- продолжительность паузы перед анимацией
- настройки анимации
- непосредственно саму анимацию
- и код, который будет выполнен по завершению анимации
Код реализации анимации приведен ниже:
rootView.transform = CGAffineTransformMakeScale(0.8f, 0.8f);
[[[UIApplication sharedApplication] keyWindow] addSubview:rootView];
[UIView animateWithDuration:0.35*0.66
delay:0.0
options:UIViewAnimationCurveEaseOut
animations:^ {
rootView.alpha = 0.66f;
rootView.transform = CGAffineTransformMakeScale(1.1f, 1.1f);
}
completion:^(BOOL completed) {
[UIView animateWithDuration:0.35*0.33
delay:0.0
options:UIViewAnimationCurveLinear
animations:^{
rootView.alpha = 1.0f;
rootView.transform = CGAffineTransformIdentity;
}
completion:^(BOOL completed) {
[UIView animateWithDuration:0.35
delay:0.9 options:UIViewAnimationCurveEaseIn
animations:^{
rootView.alpha = 0.0f;
rootView.transform = CGAffineTransformMakeScale(1.2f, 1.2f);
}
completion:^(BOOL completed) {
[rootView removeFromSuperview];
[rootView release];
}];
}];
}];
Итог
В результате написания данного класса мы получили очень удобную “оповещалку”, которую можно вызвать одной строчкой кода:
[FHNotification showMessage:@”Very simple inApp-notification”];
![](https://habrastorage.org/storage/037f2ee4/f18b4570/eb7027b9/e552124e.png)
Выводы
Плюсы данного класса:
- Очень и очень простой класс в использовании
Минусы:
Поддержка только iOS 4.0+- Возможность только текстового оповещения
Для работы данного класса так же потребуется QuartzCore.framework
Исходный код можно скачать на github, немного дополненный и расширенный
На этом всё. Спасибо за внимание