Для успеха в App Store, ваше приложение должно выделяться, не быть похожим на другие. Пользовательский интерфейс и “look and feel”, разработанные Apple и доступные программерам по умолчанию уже совсем не смотрятся на перенаселенном рынке.
Многие из наиболее популярных приложений в App Store стилизуют стандартные элементы пользовательского интерфейса:
— Twitter использует стилизованный UITabBar
— Instagram – стилизованные UITabBar и UINavigationBar
— Epicurious для iPad перенастраивает внешний вид элементов стандартного интерфейса для split-view
До выхода iOS 5, многим программистам приходилось прибегать к несколько нестандартным мерам, чтобы достичь таких результатов. Хотя использование подклассов с переопределением drawRect: было рекомендуемым подходом к изменению внешнего вида интерфейса, многие прибегали к “method swizzling”.
Но с выходом iOS 5, те темные времена ушли в прошлое! iOS 5 включает в себя множество новых API, которые вы можете использовать для легкой и непринужденной настройки внешнего вида многих элементов, доступных в UIKit.
Для иллюстрации нового API мы возьмем простое приложение о курортах для серфинга, написанное безо всяких новшеств и излишеств только с использованием стандартного пользовательского интерфейса, и превратим его в нечто более “пляжно” выглядящее.
Для того, чтобы получить максимальную отдачу от этого урока, вы должны знать основы разработки под iOS. Если вы полный новичок, вам следует ознакомиться сначала c другими уроками на этом сайте.
Итак, в путь…
Для начала, скачайте проект. Это – простое приложение, которое позволит нам сразу перейти к главной теме нашего урока — стилизации UIKit интерфейса.
Откройте проект в XCode и просмотрите код и XIB файлы. Первый экран представляет собой список курортов для серфинга, а второй отображает детальную информацию о выбранном курорте.
Попробуйте запустить приложение (кликните Build & Run или нажмите Cmd-R), чтобы увидеть с чего мы собираемся начать.
Гм… Конечно, приложение работает, как было обещано, но интерфейс явно не доносит до пользователя и малой доли того кайфа, который они вправе ожидать от серфинговых курортов. Давайте посмотрим что с этим всем можно сделать, чтобы исправить ситуацию.
Начнем с экрана с деталировкой выбранного курорта. Все на экране выглядит стандартно. Даже слишком стандартно.
Незамысловатый UIBarButtonItem на стандартном UINavigationBar наверху. Элементы UITabBar из Эпплэвского набора внизу. Опять же стандартные компоненты для ввода данных:
— UILabels с “System” Helvetica фонтом.
— UITextField
— UISlider
— UISwitch
— UISegmentedControl
Далее мы полностью перестилизуем этот экран, используя новые API предоставляемые iOS 5.
Итак, вооруженные этими благими намерениями, давайте превратим наше приложение из нуля в единицу (что, в двоичном мире, есть большая разница).
Добавление фонового изображения
Если вы заглянете в директорию Images в вашем проекте, вы обнаружите, что мы уже подготовили там несколько файлов с графикой, которые мы сможем использовать для стилизации интерфейса. Нам остается только подправить код приложения, чтобы эта графика начала работать.
В директории присутствует файл bg_sand.png, который мы и используем как фон для нашего экрана.
Откройте DetailViewController.m в проекте и создайте метод viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
[[self view] setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"bg_sand"]]];
}
Если вы еще не знакомы с такой техникой установки фонового изображения, суть ее в том, что вы можете определить цвет фона как… картинку (что мы здесь и делаем). Мы используем этот трюк для установки фона UIView, т.к. у класса UIView нет property под названием “backgroundImage”, зато есть property под названием “backgroundColor”. И это работает!
Теперь запустите приложение, чтобы проверить, что новый код работает:
Я уже чувствую песок под… вашими ногами!
Стилизация для UINavigationBar
Среди графических файлов вы найдете файлы surf_gradient_textured_32.png и surf_gradient_textured_44.png, которые мы будем использовать для стилизации навигационной панели (в дальнейшем для краткости мы будем называть ее просто навигатором). Картинки в файлах отличаются высотой, т.к. в альбомной ориентации, навигатор должен быть уже.
Мы будем отрисовывать навигатор, повторяя картинку слева направо пока не покроем всю панель.
iOS 5 предоставляет два новых API, которые помогут нам осуществить задуманное:
— У UINavigationBar появилась новая property backgroundImage, которую мы будем использовать для отрисовки наших картинок.
— У UIImage появился новый метод resizableImageWithCapInsets для создания растяжимых изображений. “CapInsets” в названии метода определяет части изображения, которые должны отображаться только один раз (не повторяться). Примером могут служить закругленные углы кнопок, которые отображаются только по краям и не участвуют в отрисовке “тела” кнопки.
Мы могли бы поместить код, стилизующий навигатор с помощью новых API, прямо в контроллер, ответственный за отрисовку текущего экрана. Но тогда нам пришлось бы копировать этот код в контроллеры всех экранов приложения, чтобы навигатор выглядел везде одинаково. Такая стилизация, очевидно, далека от идеала.
По-счастью, iOS 5 предлагает новую концепцию “appearance proxy” (прокси внешнего вида), которая позволяет настроить интерфейс один раз и распространить эти изменения на все приложение.
Начиная с навигатора, мы будем использовать “appearance proxy” для настройки ряда повторяющихся элементов пользовательского интерфейса. Давайте посмотрим во что нам станет такой подход к проблеме.
В SurfsUpAppDelegate.m, создайте новый метод прямо над методом application:didFinishLaunchingWithOptions:
- (void)customizeAppearance
{
// Создаем растяжимые изображения
UIImage *gradientImage44 = [[UIImage imageNamed:@"surf_gradient_textured_44"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
UIImage *gradientImage32 = [[UIImage imageNamed:@"surf_gradient_textured_32"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
// Устанавливаем фоновые изображение для ВСЕХ UINavigationBars навигаторов
[[UINavigationBar appearance] setBackgroundImage:gradientImage44
forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundImage:gradientImage32
forBarMetrics:UIBarMetricsLandscapePhone];
// Стилизуем текст для заголовков ВСЕХ UINavigationBars навигаторов
[[UINavigationBar appearance] setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor colorWithRed:255.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1.0],
UITextAttributeTextColor,
[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8],
UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(0, -1)],
UITextAttributeTextShadowOffset,
[UIFont fontWithName:@"Arial-Bold" size:0.0],
UITextAttributeFont,
nil]];
}
Первые две строчки создают растяжимую картинку с помощью метода resizableImageWithCapInsets, представленного выше. Обратите внимание, что этот метод в iOS5 заменил теперь устаревший метод stretchableImageWithLeftCapWidth:topCapHeight:.
Для “CapInsets” (тоже см. выше), вы обычно будете указывать размеры областей на вашей картинке (отступы в пикселах сверху, слева, снизу и справа), которые не подлежат растяжению (размножению). Все, что выпадает за пределы этих областей, будет растянуто по региону, для которого вы устанавливаете фоновую картинку. В нашем случае, мы хотим растянуть все изображение без исключений, и следовательно, устанавливаем все “CapInsets” в 0.
Следующие две строчки вызывают методы “appearance proxy”, устанавливая только что созданные нами растяжимые картинки как фоновые изображения для навигатора. Ориентация экрана, для которой устанавливается фон, указывается в параметре “forBarMetrics:”.
Последняя строка стилизует заголовок навигатора. Для этого мы используем NSDictionary c набором атрибутов для текста заголовка. Доступные ключи для атрибутов указаны ниже:
— UITextAttributeFont
— UITextAttributeTextColor
— UITextAttributeTextShadowColor
— UITextAttributeTextShadowOffset
Почти готово. Осталось добавить одну строчку с вызовом нового метода в самом начале метода application:didFinishLaunchingWithOptions:
[self customizeAppearance];
Скомпилируйте и запустите приложение. Вы должны увидеть в обеих ориентациях навигатор цвета морской волны со стилизованным заголовком!
Стилизация для UIBarButtonItem
Найдите в директории Images файлы button_textured_24.png и button_textured_30.png. Мы собираемся использовать их, чтобы стилизовать кнопки на навигаторе (UINavigationBar).
Для кнопок мы опять будем использовать растяжимые изображения. Это важно, т.к. ширина кнопок может меняться в зависимости от длины текста, размещенного на них.
Для кнопок первые и последние 5 пикселов не должны участвовать в растяжении, чтобы сформировать симпатичные закругленные левую и правую стороны. Так что мы установим соответствующие значения “CapInsets” в 5. Пикселы между этими границами будут повторены столько раз, сколько необходимо, чтобы закрасить всю ширину кнопки.
Давайте попробуем это сделать! Мы снова, как и в предыдущей главе, будем использовать “appearance proxy”, чтобы стилизовать сразу все кнопки UIBarButtonItems в нашем приложении.
Добавьте следующий код в конец метода customizeAppearance:
UIImage *button30 = [[UIImage imageNamed:@"button_textured_30"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 5)];
UIImage *button24 = [[UIImage imageNamed:@"button_textured_24"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 5)];
[[UIBarButtonItem appearance] setBackgroundImage:button30 forState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setBackgroundImage:button24 forState:UIControlStateNormal
barMetrics:UIBarMetricsLandscapePhone];
[[UIBarButtonItem appearance] setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor colorWithRed:220.0/255.0 green:104.0/255.0 blue:1.0/255.0 alpha:1.0],
UITextAttributeTextColor,
[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0],
UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(0, 1)],
UITextAttributeTextShadowOffset,
[UIFont fontWithName:@"AmericanTypewriter" size:0.0],
UITextAttributeFont,
nil]
forState:UIControlStateNormal];
Все здесь уже выглядит знакомо. Мы создаем растяжимые изображения и устанавливаем их как фон для кнопок в обеих ориентациях экрана (портретной и альбомной). Затем мы форматируем фонт для текста на кнопках, чтобы он соответствовал стилю фонта (typewriter), который вы видели на картинках в самом начале урока.
Кнопка “back” на навигаторе требует специального подхода при стилизации, т.к. она должна выглядеть несколько по-другому – указывать назад. Взгляните на картинки, которые мы собираемся использовать для этого, чтобы лучше понять что здесь имеется ввиду: Imagesbutton_back_textured_24.png и Imagesbutton_back_textured_30.png.
Добавьте следующий код в конец метода customizeAppearance для стилизации кнопки “back” на навигаторе:
UIImage *buttonBack30 = [[UIImage imageNamed:@"button_back_textured_30"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 5)];
UIImage *buttonBack24 = [[UIImage imageNamed:@"button_back_textured_24"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 5)];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:buttonBack30
forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:buttonBack24
forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
Обратите внимание, что мы использовали другие значения для “CapInsets” потому, что у кнопки “back” левая сторона, которая не должна участвовать в растяжении, шире, чем у обычной кнопки. Также обратите внимание, что мы используем специальную property UIBarButtonItem под названием “backButtonBackgroundImage”.
Запустите приложение, и вы увидите отменные стилизованные кнопки UIBarButtonItems на вашем навигаторе!
Стилизация для UITabBar
Для стилизации UITabBar, iOS 5 предлагает API для изменения фонового изображения самого UITabBar, а также изображения, которое используется для выделения выбранного элемента (таба, или закладки – как вам привычнее). В качестве этих изображений мы будем использовать картинки из файлов Imagestab_bg.png и Imagestab_select_indicator.png. Потратьте пару минут, чтобы взглянуть на них.
Хотя наш прототип приложения использует только один UITabBar, мы могли бы решить добавить еще один-два позже. Наиболее вероятно, что в этом случае мы бы стилизовали их всех точно так же, как этот наш первый. Так что, мы опять попользуем “appearance proxy” подход, чтобы стилизовать все UITabBar в нашем приложении одинаково.
Добавьте следующий код в конец метода customizeAppearance:
UIImage *tabBackground = [[UIImage imageNamed:@"tab_bg"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
[[UITabBar appearance] setBackgroundImage:tabBackground];
[[UITabBar appearance] setSelectionIndicatorImage:
[UIImage imageNamed:@"tab_select_indicator"]];
Скомпилируйте и запустите опять… Прекрасно! Фон для UITabBar и картинка для выбранного элемента будут достойным добавлением к нашему интерфейсу.
Обратите внимание, что вы также можете указать “finished” и “unfinished” картинки, если вы хотите изменить способ появления изображений для выбранного и не выбранных элементов на UITabBar.
Стилизация для UISlider
Откройте файлы Imagesslider_minimum.png, Imagesslider_maximum.png и Imagesthumb.png, чтобы ознакомиться с картинками, которые мы будем использовать для стилизации UISlider.
iOS 5 делает стилизацию UISlider до неприличия простой – достаточно просто установить 3 property для UISlider: “maximumTrackImage”, “minimumTrackImage” и “thumbImage”.
Давайте попробуем. Добавьте следующий код в конец метода customizeAppearance:
UIImage *minImage = [[UIImage imageNamed:@"slider_minimum.png"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 0)];
UIImage *maxImage = [[UIImage imageNamed:@"slider_maximum.png"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 0)];
UIImage *thumbImage = [UIImage imageNamed:@"thumb.png"];
[[UISlider appearance] setMaximumTrackImage:maxImage
forState:UIControlStateNormal];
[[UISlider appearance] setMinimumTrackImage:minImage
forState:UIControlStateNormal];
[[UISlider appearance] setThumbImage:thumbImage
forState:UIControlStateNormal];
Скомпилируйте, запустите и насладитесь своим классным, стильным слайдером!
Стилизация для UISegmentedControl
Теперь мы займемся стилизацией UISegmentedControl (или просто сегментного переключателя). Стилизация этого компонента слегка сложнее, поскольку нам нужны фоновые картинки для включенного и выключенного состояния, а также отрисовка всевозможных комбинаций (т.е. вкл. слева/выкл. справа, выкл. слева/вкл. справа, выкл. на обеих сторонах).
Взгляните на картинки, чтобы вышесказанное стало яснее: Imagessegcontrol_sel.png, Imagessegcontrol_uns.png, Imagessegcontrol_sel-uns.png и Imagessegcontrol_uns-uns.png.
Затем, добавьте следующий код в конец метода customizeAppearance:
UIImage *segmentSelected =
[[UIImage imageNamed:@"segcontrol_sel.png"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 15)];
UIImage *segmentUnselected =
[[UIImage imageNamed:@"segcontrol_uns.png"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 15)];
UIImage *segmentSelectedUnselected =
[UIImage imageNamed:@"segcontrol_sel-uns.png"];
UIImage *segUnselectedSelected =
[UIImage imageNamed:@"segcontrol_uns-sel.png"];
UIImage *segmentUnselectedUnselected =
[UIImage imageNamed:@"segcontrol_uns-uns.png"];
[[UISegmentedControl appearance] setBackgroundImage:segmentUnselected
forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setBackgroundImage:segmentSelected
forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segmentUnselectedUnselected
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segmentSelectedUnselected
forLeftSegmentState:UIControlStateSelected
rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance]
setDividerImage:segUnselectedSelected
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateSelected
barMetrics:UIBarMetricsDefault];
Скомпилируйте, запустите и ваш UISegmentedControl приобретет совершенно иной вид!
Стилизация для UISwitch
На момент написания этого урока нет простого способа стилизации фонового изображения для UISwitch. Однако (как и для многих других элементов) очень легко поменять его цвет через property tintColor.
Чтобы продемонстрировать различные подходы к стилизации, мы в этот раз поменяем в нашем коде параметр “onTintColor”. Обратите внимание, что мы уже заранее подключили IBOutlet с именем rentSwitch в DetailViewController к нашему элементу UISwitch в DetailView.xib.
Так что просто добавьте следующий код для изменения цвета подкраски в метод viewDidLoad в DetailViewController:
[rentSwitch setOnTintColor:[UIColor colorWithRed:0 green:175.0/255.0 blue:176.0/255.0 alpha:1.0]];
Запустите приложение и оцените новый, свежеподкрашенный UISwitch!
Все теперь выглядит очень даже неплохо, но у нас осталась еще пара неохваченных элементов интерфейса. Нам надо научиться стилизовать ярлыки (labels) и изменять фон для UITextField.
Стилизация для UILabel
Ярлык – один из элементов на нашем экране, который мы НЕ будем стилизовать через “appearance proxy”. Откройте DetailView.xib, и мы изменим их вид прямо в Interface Builder. Сначала на основном экране в Interface Builder выберите первый ярлык (т.е “Your name”). Затем, на правой панели зайдите в Attributes Inspector и поменяйте следующие атрибуты:
— Font: Custom
— Family: American Typewriter
— Style: Regular
— Size: 16
Повторите то же для остальных ярлыков: “Experience Level” и “Rent a board?”.
Скомпилируйте и запустите приложение. Теперь текст на ярлыках прорисовывается новым, аккуратным, симпатичным шрифтом!
Стилизация для UITextField
Наш UITextField элемент уже использует UITextBorderStyleLine стиль. Поскольку мы все еще в Interface Builder, давайте установим для него новый фонт: American Typewriter, Size 12, Regular.
Если вы загляните в Identity Inspector, вы увидите, что в поле Custom Class, класс для нашего поля определен не как UITextField, а как CustomTextField. В навигаторе проекта (левая панель) откройте группу с названием Custom Views. В этой группе мы уже создали класс с таким же именем – CustomTextField.
Пока метод drawRect: нашего UITextField делегирует всю прорисовку супер-классу. Но для того, чтобы закрасить фон цветом морской волны, нам прийдется переопределить этот метод (что есть не что иное, как еще одна техника стилизации).
Замените вызов супер-класса на следующий код:
- (void)drawRect:(CGRect)rect
{
UIImage *textFieldBackground = [[UIImage imageNamed:@"text_field_teal.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(15.0, 5.0, 15.0, 5.0)];
[textFieldBackground drawInRect:[self bounds]];
}
Здесь мы создаем уже знакомое нам растяжимое изображение с подходящими значениями “CapInsets” и зарисовываем им прямоугольную область нашего UITextField.
Давайте скомпилируем и посмотрим на результат…
Наши поздравления! Ваш экран полностью стилизован!
Автор: MicRaiS