Войти

Или войди с помощью

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

Разработка
Никита Narmo Дёнин avatar |
Всплывающие сообщения для 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 пикселей).

Теперь нужно создать контейнер 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]. Все действия с объектами интерфейса, помещённые в этот блок, будут анимироваться (точнее, не совсем все; ниже я приведу пример, где анимация работать не будет):

[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.

70
undefined
iPhones.ru
Для отображения всплывающих сообщений в iOS есть только один компонент — UIAlertView. Им очень удобно пользоваться, ведь создать и отобразить его можно буквально двумя-тремя строчками кода. Но у него есть один изъян: он блокирует интерфейс до того момента, пока пользователь не нажмёт кнопку, чтобы принудительно скрыть его. А иногда программисту всего лишь нужно показать какое-либо...

70 комментариев

Котик
Котик
Котик
Котик
Котик
Котик
Котик
Котик
Котик
Котик
Котик
Котик
Котик из TikTok
Котик из TikTok
Котик из TikTok
Котик из TikTok
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Момент из фильма
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Мем стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Офис стикер
Видео мем
Видео мем
Видео мем
Видео мем
Видео мем
Видео мем

Какие правила в комментариях
  1. iFanatik avatar
    iFanatik 8 апреля 2011
    0

    Спасибо за реально интересную статью. Давно таких не было.

    i.band avatar
    i.band8 апреля 2011
    0

    А вот интересно, разве всплывающие уведомления которые при изменении звука или при блокировке ориентации появляются, например, использовать нельзя для подобной цели?

    Войди на сайт, чтобы ответить
    Ответить
  2. Vizakenjack avatar
    Vizakenjack 8 апреля 2011
    0

    Отличная статья. Стоит на хабре запостить, хотя бы в песочницу

    iL0bster avatar
    iL0bster8 апреля 2011
    0

    @Vizakenjack, на хабр уже не получится: там копипаст даже своего контента запрещён. А вот как топик-ссылку… Кстати, статья великолепна! А то уже устал читать про птиц злобных. Побольше бы таких статей!

    Войди на сайт, чтобы ответить
    Ответить
  3. Theodore Plesha avatar
    Theodore Plesha 8 апреля 2011
    0

    Вообщето разрешение iPhone 4 960×640.

    Никита Narmo Дёнин avatar
    0

    @Theodore Plesha, На программном уровне в iPhone оно 320×480 для любого экрана.

    i.band avatar
    i.band8 апреля 2011
    0

    @Никита Narmo Дёнин, ненене. разрешение будет 960 на 640 пикселей, но 320 на 240 поинтов. Это сделано для удобства разработчиков, т.к. 1 поинт на 4м айфоне будет считаться за квадрат 2 на 2 пикселя, а на 3Гс — за один пиксель.
    Однако есть @property CGFloat contentScaleFactor; которое возвращает «масштаб» (сколько пикселей в поинте для данного view на экране).
    Так что можно использовать и пиксели, но обычно они используются для 3Д объектов, например. А для задания размеров как в нашем примере — поинты :)

    Никита Narmo Дёнин avatar
    0

    @i.band, Я про поинты и говорил как раз.

    i.band avatar
    i.band8 апреля 2011
    0

    @Никита Narmo Дёнин, я понял)) просто решил еще раз расставить все точки над i :)

    PS спасибо за статью. очень нравятся такие статьи.
    PPS там наверху коммент оставил про всплывающие полупрозрачные нотификаторы (при изменении громкости боковыми кнопками и тп). они доступны в API? их можно для подобной цели использовать? :)

    Никита Narmo Дёнин avatar
    0

    @i.band, Нет, к сожалению.

    Войди на сайт, чтобы ответить
    Ответить
  4. DinckelMan avatar
    DinckelMan 8 апреля 2011
    0

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

    Войди на сайт, чтобы ответить
    Ответить
  5. TauruS_iPhone4_now avatar
    TauruS_iPhone4_now 8 апреля 2011
    0

    Хорошая статья.
    Надеюсь в будущем такие статьи будут появляться еще

    Никита Narmo Дёнин avatar
    0

    @TauruS_iPhone4_now, Я тоже надеюсь :-) Надо придумать, о чём ещё написать.

    iL0bster avatar
    iL0bster8 апреля 2011
    0

    @Никита Narmo Дёнин, идея: Такой твик в сидию :)

    Никита Narmo Дёнин avatar
    0

    @iL0bster, Не, тут я пас.

    iL0bster avatar
    iL0bster8 апреля 2011
    0

    @Никита Narmo Дёнин, а что так? Многие были бы довольны.

    Никита Narmo Дёнин avatar
    0

    @iL0bster, Я на таком низком уровне не пишу. Я больше по прикладным приложениям.

    andreykalol avatar
    andreykalol9 апреля 2011
    0

    @Никита Narmo Дёнин, Не ужели всё так принципиально?
    Я вот бы тоже не отказался от такого твика)

    vetok avatar
    vetok8 апреля 2011
    0

    @Никита Narmo Дёнин, надо придумать как это прикрутить в айос

    Войди на сайт, чтобы ответить
    Ответить
  6. Yogi avatar
    Yogi 8 апреля 2011
    0

    Спасибо за статью! Надеюсь вы дальше тоже будите выкладывать подобные уроки, очень полезно!

    Войди на сайт, чтобы ответить
    Ответить

Нашли орфографическую ошибку в новости?

Выделите ее мышью и нажмите Ctrl+Enter.