Разработка Всплывающие сообщения для iOS

Для отображения всплывающих сообщений в iOS есть только один компонент — UIAlertView. Им очень удобно пользоваться, ведь создать и отобразить его можно буквально двумя-тремя строчками кода. Но у него есть один изъян: он блокирует интерфейс до того момента, пока пользователь не нажмёт кнопку, чтобы принудительно скрыть его. А иногда программисту всего лишь нужно показать какое-либо информационное сообщение, не требующее от пользователя никаких действий. В Android это решено с помощью компонента Toast, в который передаётся текст сообщения (а при необходимости и координаты, в которых оно должно отобразиться).

В одном из своих проектов мне нужно было отображать сообщения именно таким образом. И под впечатлением от Toast для Android я сделал собственный компонент, выводящий на экран всплывающие уведомления.

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

Вот задачи, которые я возложил на свой «тостер»:

– отобразить сообщение с анимацией
– подождать 1 секунду
– скрыть сообщение с анимацией

Я сконструировал объект-тостер так, чтобы он создавался и отображался одной строчкой кода:

[WToast showWithText:text];

После вызова этого метода объект сам контролирует своё поведение (появление, ожидание и скрытие). Прежде всего нам надо создать текстовую метку, которая и будет содержать наш текст. Так как текст может быть любой длины, придётся динамически обсчитывать размеры создаваемого компонента UILabel. Для этого в фреймворке UIKit есть специальный метод для объектов NSString, позволяющий узнать размеры текста при заданных шрифте, ширине и типе переноса строк.

Итак, создаём объект UILabel и вычисляем размеры текста:

UILabel *textLabel = [[UILabel alloc] init]; textLabel.backgroundColor = [UIColor clearColor]; textLabel.textAlignment = UITextAlignmentCenter; textLabel.font = [UIFont systemFontOfSize:14]; textLabel.textColor = RGB(255, 255, 255); textLabel.numberOfLines = 0; textLabel.lineBreakMode = UILineBreakModeWordWrap; CGSize sz = [text sizeWithFont:textLabel.font constrainedToSize:CGSizeMake(width — 20.0f, 9999.0f) lineBreakMode:textLabel.lineBreakMode];

Свойство numberOfLines, выставленное в 0, указывает метке, что количество строк в ней не ограничено. Свойство lineBreakMode сообщает, что при достижении правой границы будет происходить перенос по словам (это нужно, чтобы окончание строки не превратилось в многоточие). В методе -sizeWithFont:constrainedToSize:lineBreakMode: параметр constrainedToSize указывает максимальный размер будущей текстовой метки. Передав туда высоту 9999 пикселей, я гарантировано получу метку без многоточий в конце строки (ведь высота экрана iPhone составляет всего 480 пикселей).

Читайте также  Apple уравнивает цены в App Store

Теперь нужно создать контейнер WToast (который я сделал наследником UIView), добавить ему полупрозрачный фон (так он смотрится красивее, чем если бы был непрозрачным), скруглить углы, поместить на него текстовую метку и отобразить его на экране.

Создаём контейнер:

CGRect tmpRect; tmpRect.size.width = width; tmpRect.size.height = MAX(sz.height + 20.0f, 38.0f); tmpRect.origin.x = floor((screenWidth — width) / 2.0f); tmpRect.origin.y = floor(screenHeight — tmpRect.size.height — 15.0f); WToast *toast = [[WToast alloc] initWithFrame:tmpRect]; toast.backgroundColor = RGBA(0, 0, 0, 0.8f);

Обратите внимание на указание координат x и y для метки. Все координаты в iOS представлены типом float, который может принимать дробные значения. Если какому-либо элементу интерфейса задать дробные координаты, он отобразится «замыленным» (кстати, некоторые приложения в App Store грешат этим; даже в приложении от Apple для iTunes Connect была такая проблема). Во избежание этого эффекта нужно округлять координаты до целого значения. Функция floor округлит значение до нижней целой границы — то есть просто отбросит дробную часть.

RGBA — это макрос, который я написал для преобразования параметров RGB и alpha в UIColor. Он делает код компактнее и позволяет работать с RGB в привычном диапазоне 0..255 (а не 0..1, как это сделано в UIColor). Сравните размеры строки с оригинальным вызовом UIColor:

UIColor *blackTransparentColor = RGBA(0, 0, 0, 0.8f);
UIColor *blackTransparentColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.8f];

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

Мы получили наследника UIView чёрного цвета и с прозрачностью 0.8. Теперь нужно скруглить ему углы (иначе он будет выглядеть очень топорно). Для скругления можно воспользоваться инструментами, доступными в фреймворке QuartzCore. Подключаем заголовочный файл QuartzCore/QuartzCore.h и фреймворк QuartzCore и делаем следующее:

CALayer *layer = toast.layer; layer.masksToBounds = YES; layer.cornerRadius = 5.0f;

Параметр cornerRadius объекта CALayer задаёт радиус скругления. Попробуйте поиграться с его значением и увидите, как будет изменяться рамка нашего уведомления.

Контейнер сообщения готов, текстовую метку мы создали в самом начале — собираем это всё воедино:

textLabel.text = text; tmpRect.origin.x = floor((toast.frame.size.width — sz.width) / 2.0f); tmpRect.origin.y = floor((toast.frame.size.height — sz.height) / 2.0f); tmpRect.size = sz; textLabel.frame = tmpRect; [toast addSubview:textLabel]; [textLabel release]; toast.alpha = 0.0f;

После выполнения этого кода наш новорожденный объект toast будет полностью прозрачным (toast.alpha = 0.0f). Это сделано для дальнейшей анимации появления.

Для запуска анимации можно воспользоваться простейшим способом, предусмотренным разработчиками iOS — блоком [UIView beginAnimations:context:] .. [UIView commitAnimations]. Все действия с объектами интерфейса, помещённые в этот блок, будут анимироваться (точнее, не совсем все; ниже я приведу пример, где анимация работать не будет):

Читайте также  App Store Astronut: миссия выполнима

[UIView beginAnimations:@»show» context:nil]; [UIView setAnimationDelegate:self]; [UIView setAnimationDuration:0.2f]; [UIView setAnimationDidStopSelector:@selector(__animationDidStop:__finished:__context:)]; self.alpha = 1.0f; [UIView commitAnimations];

Здесь мы задаём делегата, которому будет сообщено об окончании процесса анимации, продолжительность анимации и действия, которые нужно анимировать. В нашем случае это перевод объекта toast из полностью прозрачного состояния в полностью непрозрачное (self.alpha = 1.0f).

Вот что мы увидим на экране в результате выполнения нашей программы:

В методе -__animationDidStop:__finished:__context:, который вызовется по окончании анимации, включается секундный таймер, запускающий скрытие нашего сообщения:

[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(__hide) userInfo:nil repeats:NO];

Скрытие сообщения также будет анимированным:

[UIView beginAnimations:@»hide» context:nil]; [UIView setAnimationDelegate:self]; [UIView setAnimationDuration:0.8f]; [UIView setAnimationDidStopSelector:@selector(__animationDidStop:__finished:__context:)]; self.alpha = 0.0f; [UIView commitAnimations];

После этого объект можно удалить с экрана, вызвав метод removeFromSuperview.

Если поместить вызов removeFromSuperview в блок анимации, то исчезновение не будет анимироваться, объект исчезнет сразу после вызова этого метода. Поэтому сначала делаем «тостер» полностью прозрачным (self.alpha = 0.0f), а затем, в селекторе окончания анимации, убираем объект с экрана.

Весь цикл работы компонента будет выглядеть так:

Не забывайте о том, что все действия, связанные с элементами пользовательского интерфейса, должны выполняться в главном потоке.

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

Исходные коды компонента WToast и тестовый проект можно загрузить с github. Этот компонент можно свободно использовать в любом вашем проекте без указания авторства. Он распространяется на условиях Public Domain.

Источник: iphones.ru

TRAVEL