Обсуждение

Обсуждение

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

В Core Graphics программист может создавать градиенты двух типов: осевой и радиальный (но мы обсудим только осевые градиенты). Осевой градиент начинается в определенной точке с одного цвета и заканчивается в другой точке иным цветом (конечно, градиент можно и начать и закончить одним и тем же цветом, но тогда он будет не слишком напоминать градиент). «Осевой» означает «относящийся к оси». Между двумя точками (начальной и конечной) создается сегмент линии, он и будет той осью, вдоль которой отрисовывается градиент. Образец осевого градиента показан на рис. 17.27. На самом деле это осевой градиент, начинающийся с голубого цвета и заканчивающийся зеленым, но на черно-белой иллюстрации этого, конечно же, не видно.

Рис. 17.27. Осевой градиент

Чтобы создать осевой градиент, вызовите функцию CGGradientCreateWithColorComponents. Возвращаемым значением этой функции будет новый градиент типа CGGradientRef. Это описатель градиента. Закончив работать с градиентом, необходимо вызвать процедуру CGGradientRelease, передав описатель тому градиенту, который вы ранее получили от CGGradientCreateWithColorComponents.

Функция CGGradientCreateWithColorComponents принимает четыре параметра.

• Цветовое пространство — это контейнер для цветового диапазона, он должен относиться к типу CGColorSpaceRef. Для этого параметра можем просто передать возвращаемое значение функции CGColorSpaceCreateDeviceRGB — и получим пространство цветов RGB.

 Массив цветовых компонентов (подробнее об этом — в разделе 17.3) — здесь должны содержаться значения красного, зеленого, голубого цветов и альфа-значение, все они относятся к типу CGFloat. Количество элементов в массиве тесно связано со значениями следующих двух параметров. Вы должны будете включить в этот массив такое количество значений, которого будет достаточно для того, чтобы указать ряд положений, обозначенных в четвертом параметре. Так, если вы запрашиваете только два положения (начальную и конечную точки), то в этом массиве должно быть минимум два цвета. А поскольку в состав каждого цвета входят красный, зеленый, голубой компоненты, а также альфа-значение, в данном массиве должно быть 2 ? 4 элемента: четыре для первого цвета и четыре — для второго. Не волнуйтесь, если пока не все понимаете, — все встанет на свои места после изучения примеров.

 Положения оттенков в цветовом массиве — этот параметр определяет, как быстро в градиенте осуществляется переход от одного оттенка к другому. Количество элементов должно быть таким же, как и значение четвертого параметра. Например, если вы запрашиваете четыре цвета и хотите, чтобы первый цвет был начальным цветом градиента, а последний цвет располагался в конце градиента, то нужно предоставить массив из двух элементов типа CGFloat, где первый элемент имеет значение 0.0f (как в первом компоненте цветового массива), а второй элемент — 3.0f (как в четвертом компоненте цветового массива). Значения двух промежуточных цветов определяют, в каком именно порядке расположены в градиенте оттенки, лежащие между начальным и конечным цветами. Опять же не волнуйтесь, если это сложно сразу усвоить. Я приведу много примеров, на которых вся концепция станет совершенно ясна.

 Количество положений — здесь мы указываем, сколько цветов и положений должно быть в градиенте.

Рассмотрим пример. Предположим, мы хотим нарисовать градиент, который показан на рис. 17.27. Вот как это делается.

1. Выбираем начальную и конечную точки градиента — ось, вдоль которой будут изменяться оттенки. В данном случае я указываю переход слева направо. Представьте, что цвет изменяется по мере движения вдоль гипотетической линии. Цвета будут располагаться по оси так, что любая вертикальная линия, перпендикулярно пересекающая ось градиента, будет пролегать только по одному оттенку. В случае, показанном на рис. 17.27, любая вертикальная линия будет перпендикулярна оси градиента. Рассмотрим эти вертикальные линии подробнее. Действительно, в любой ее точке цвет градиента один и тот же. Вот так и строится градиент. Хорошо, хватит теории — переходим ко второму этапу.

2. Теперь нам нужно создать цветовое пространство, которое будет передано функции CGGradientCreateWithColorComponents в первом параметре, как было объяснено ранее:

CGColorSpaceRef colorSpace =

CGColorSpaceCreateDeviceRGB();

Закончив работу с этим цветовым пространством, мы избавимся от него.

3. Зададим голубой в качестве начального цвета (слева), а зеленый — в качестве конечного (справа), как показано на рис. 17.27. Названия, которыми я пользуюсь (startColorComponents и endColorComponents), выбраны произвольно и помогают нам не забыть о положении каждого цвета. Для указания того, какой цвет будет находиться в начале, а какой — в конце, мы воспользуемся позициями из массива:

UIColor *startColor = [UIColor blueColor];

CGFloat *startColorComponents =

(CGFloat *)CGColorGetComponents([startColor CGColor]);

UIColor *endColor = [UIColor greenColor];

CGFloat *endColorComponents =

(CGFloat *)CGColorGetComponents([endColor CGColor]);

Если вы забыли, какая концепция лежит в основе цветовых компонентов, вернитесь к этому вопросу, изложенному в разделе 17.3, а потом продолжайте читать.

4. Получив компоненты каждого цвета, мы помещаем все их в одномерный массив, который будет передан функции CGGradientCreateWithColorComponents:

CGFloat colorComponents[8] = {

/* Четыре компонента оранжевого цвета (RGBA) */

startColorComponents[0],

startColorComponents[1],

startColorComponents[2],

startColorComponents[3], /* Первый цвет = оранжевый */

/* Четыре компонента голубого цвета (RGBA) */

endColorComponents[0],

endColorComponents[1],

endColorComponents[2],

endColorComponents[3], /* Второй цвет = голубой */

};

5. Поскольку у нас в этом массиве всего два цвета, следует указать, что первый цвет расположен в самом начале градиента (точка с координатами (0; 0)) а второй — в самом конце (точка (1; 0)). Итак, поместим эти показатели в массив, предназначенный для передачи функции CGGradientCreateWithColorComponents:

CGFloat colorIndices[2] = {

0.0f, /* Цвет 0 в массиве colorComponents */

1.0f, /* Цвет 1 в массиве colorComponents */

};

6. Теперь нам остается просто вызвать функцию CGGradientCreateWithColorComponents со всеми сгенерированными значениями:

CGGradientRef gradient =

CGGradientCreateWithColorComponents

(colorSpace,

(const CGFloat *)&colorComponents,

(const CGFloat *)&colorIndices,

2);

7. Прекрасно! Теперь в переменной gradient находится объект градиента. Пока не забыли, нужно высвободить цветовое пространство, созданное с помощью функции CGColorSpaceCreateDeviceRGB:

CGColorSpaceRelease(colorSpace);

Теперь воспользуемся процедурой CGContextDrawLinearGradient для отрисовки осевого градиента в графическом контексте. Эта процедура принимает пять параметров.

• Графический контекст — указывает графический контекст, в котором будет отрисовываться осевой градиент.

 Осевой градиент — описатель объекта осевого градиента. Этот объект градиента создан с помощью функции CGGradientCreateWithColorComponents.

 Начальная точка — точка в графическом контексте, указанная в параметре CGPoint, в которой начинается градиент.

 Конечная точка — точка в графическом контексте, указанная в параметре CGPoint, в которой заканчивается градиент.

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

• kCGGradientDrawsAfterEndLocation — распространяет градиент на все точки после конечной точки градиента;

• kCGGradientDrawsBeforeStartLocation — распространяет градиент на все точки до начальной точки градиента;

• 0 — градиент не распространяется.

Чтобы распространить градиент в обе стороны, укажите оба параметра — «до» и «после», — воспользовавшись логическим оператором ИЛИ (обозначается символом |). Пример будет рассмотрен далее:

CGRect screenBounds = [[UIScreen mainScreen] bounds];

CGPoint startPoint, endPoint;

startPoint = CGPointMake(0.0f,

screenBounds.size.height / 2.0f);

endPoint = CGPointMake(screenBounds.size.width,

startPoint.y);

CGContextDrawLinearGradient

(currentContext,

gradient,

startPoint,

endPoint,

0);

CGGradientRelease(gradient);

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

Очевидно, что результат выполнения этого кода будет напоминать рис. 17.27. Поскольку мы начали градиент с самой левой точки экрана и распространили его до самой правой, то не можем воспользоваться теми значениями, которые способен получить последний параметр процедуры CGContextDrawLinearGradient, параметр отрисовки градиента. Исправим этот недостаток. Попробуем нарисовать такой градиент, как на рис. 17.28.

Рис. 17.28. Осевой градиент с оттенками, распространяющимися за его начальную и конечную точки

При написании кода воспользуемся той же процедурой, о которой говорили ранее:

— (void)drawRect:(CGRect)rect{

CGContextRef currentContext = UIGraphicsGetCurrentContext();

CGContextSaveGState(currentContext);

CGColorSpaceRef colorSpace =

CGColorSpaceCreateDeviceRGB();

UIColor *startColor = [UIColor orangeColor];

CGFloat *startColorComponents =

(CGFloat *)CGColorGetComponents([startColor CGColor]);

UIColor *endColor = [UIColor blueColor];

CGFloat *endColorComponents =

(CGFloat *)CGColorGetComponents([endColor CGColor]);

CGFloat colorComponents[8] = {

/* Четыре компонента оранжевого цвета (RGBA (RGBA) */

startColorComponents[0],

startColorComponents[1],

startColorComponents[2],

startColorComponents[3], /* Первый цвет = оранжевый */

/* Четыре компонента голубого цвета (RGBA) */

endColorComponents[0],

endColorComponents[1],

endColorComponents[2],

endColorComponents[3], /* Второй цвет = голубой */

};

CGFloat colorIndices[2] = {

0.0f, /* Цвет 0 в массиве colorComponents */

1.0f, /* Цвет 1 в массиве colorComponents */

};

CGGradientRef gradient = CGGradientCreateWithColorComponents

(colorSpace,

(const CGFloat *)&colorComponents,

(const CGFloat *)&colorIndices,

2);

CGColorSpaceRelease(colorSpace);

CGPoint startPoint, endPoint;

startPoint = CGPointMake(120,

260);

endPoint = CGPointMake(200.0f,

220);

CGContextDrawLinearGradient (currentContext,

gradient,

startPoint,

endPoint,

kCGGradientDrawsBeforeStartLocation |

kCGGradientDrawsAfterEndLocation);

CGGradientRelease(gradient);

CGContextRestoreGState(currentContext);

}

Возможно, вам не совсем понятно, как при смешивании значений kCGGradientDrawsBeforeStartLocation и kCGGradientDrawsAfterEndLocation, переданных процедуре CGContextDrawLinearGradient, получается диагональный эффект, как на рис. 17.28. Поэтому уберем эти значения и зададим для этого параметра процедуры CGContextDrawLinearGradient значение 0 — как и раньше. Результат получится как на рис. 17.29.

Рис. 17.29. Осевой градиент без распространения цветов

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

Данный текст является ознакомительным фрагментом.



Поделитесь на страничке

Следующая глава >

Похожие главы из других книг:

Обсуждение

Из книги автора

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


Обсуждение

Из книги автора

Обсуждение Фреймворк Assets Library — удобный посредник между разработчиком и библиотекой фотографий. Как будет указано в разделе 13.6, в iOS SDK вам предоставляются встроенные компоненты графического пользовательского интерфейса, которыми можно пользоваться для доступа к


Обсуждение

Из книги автора

Обсуждение Чтобы пользователь мог выбирать фотоснимки или видеоролики из своей библиотеки фотографий, необходимо установить свойство sourceType экземпляра UIImagePickerController в значение UIImagePickerControllerSourceTypePhotoLibrary и только потом открывать перед пользователем инструмент для выбора


Обсуждение

Из книги автора

Обсуждение Библиотека ресурсов подразделяется на группы. В каждой группе содержатся ресурсы, а каждый ресурс имеет свойства, например URL (универсальные локаторы ресурсов) и объекты представления.Все ресурсы всех типов можно получать из библиотеки ресурсов с помощью


Обсуждение

Из книги автора

Обсуждение Класс UIVideoEditorController, содержащийся в iOS SDK, позволяет программисту вывести на экран перед пользователем специальный интерфейс для редактирования. Все, что требуется сделать, — предоставить URL видеоролика, который предполагается отредактировать, а потом


Обсуждение

Из книги автора

Обсуждение В зависимости от того, на работу в какой версии iOS рассчитано ваше приложение, его можно запускать и выполнять на различных устройствах, где установлены разные версии iOS. Например, вы можете разрабатывать приложение в последней версии iOS SDK, но в качестве целевой


Обсуждение

Из книги автора

Обсуждение Когда приложение переходит в фоновый режим, работа его основного потока приостанавливается. Потоки, которые вы создаете в своем приложении с помощью метода класса detachNewThreadSelector: toTarget: withObject:, относящегося к классу NSThread, также приостанавливаются. Если вы


Обсуждение

Из книги автора

Обсуждение Многие приложения, ежедневно поступающие на рынок App Store, обладают возможностями соединения с теми или иными серверами. Некоторые выбирают с сервера данные для обновления, другие отсылают информацию на сервер и т. д. В течение долгого времени в iOS существовал


Обсуждение

Из книги автора

Обсуждение В iOS приложение может запросить продолжить воспроизведение своих аудиофайлов, даже если оно само переходит в фоновый режим. В этом разделе мы воспользуемся плеером AVAudioPlayer, который прост и удобен в обращении. Наша задача — запустить аудиоплеер и воспроизвести


Обсуждение

Из книги автора

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


Обсуждение

Из книги автора

Обсуждение Допустим, пустое приложение iOS (то есть приложение всего с одним окном, для которого еще не написан код) впервые запускается на устройстве с iOS, поддерживающем работу в многозадачном режиме. Оно запускается именно впервые, а не возвращается из фонового режима в


Обсуждение

Из книги автора

Обсуждение При работе с приложениями, которые используют класс NSURLConnection, но, уходя в фоновый режим, не запрашивают у iOS дополнительного времени, обращаться с соединениями не составляет никакого труда. Рассмотрим на примере, как будет действовать асинхронное соединение,


Обсуждение

Из книги автора

Обсуждение Пока ваше приложение работает в фоновом режиме, может произойти многое! Например, пользователь может вдруг изменить локализацию устройства с iOS на странице Settings (Настройки) и задать, к примеру, испанский язык вместо английского. Приложения могут


Обсуждение

Из книги автора

Обсуждение В приложениях, написанных для iOS, файл пакета настроек может быть предоставлен пользователю для внесения собственных настроек. Эти настройки будут доступны пользователю в приложении (Settings) на устройстве. Чтобы лучше понять, как работает этот механизм,


Обсуждение

Из книги автора

Обсуждение Пуш-уведомления похожи на локальные уведомления тем, что позволяют сообщать пользователю определенную информацию, даже если ваше приложение неактивно при поступлении уведомления. В то время как локальные уведомления назначаются самим приложением,