iOS. Приемы программирования — страница 111 из 124

Постановка задачи

Требуется просто рисовать линии в графическом контексте.

Решение

Получите описатель для вашего графического контекста, а потом пользуйтесь функциями CGContextMoveToPoint и CGContextAddLineToPoint для отрисовки линии.

Обсуждение

Когда мы говорим о рисовании фигур в iOS или OS X, мы подразумеваем пути (paths). Что такое путь в данном случае? Путь возникает между одной или несколькими сериями точек, расположенными на экране. Между путями и линиями существует значительная разница. Путь может содержать несколько линий, но линия не может содержать несколько путей. Считайте, что путь — это просто серия точек.

Линии нужно рисовать, пользуясь путями. Укажите начальную и конечную точки пути, а потом прикажите Core Graphics заполнить этот путь за вас. Core Graphics считает, что вы создали линию вдоль этого пути, и нарисует его указанным вами цветом (см. раздел 17.3).

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

1. Выбрать цвет в вашем графическом контексте (см. раздел 17.3).

2. Получить описатель графического контекста — это делается с помощью функции UIGraphicsGetCurrentContext.

3. Задать начальную точку для линии, воспользовавшись процедурой CGContextMoveToPoint.

4. Переместить перо в графическом контексте, воспользовавшись процедурой CGContextAddLineToPoint, и указать конечную точку линии.

5. Создать намеченный путь с помощью процедуры CGContextStrokePath. Эта процедура отрисует путь в графическом контексте, использовав указанный вами цвет.


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

В iOS толщина линии измеряется в логических точках.

Вот пример:


— (void)drawRect:(CGRect)rect{


/* Задаем цвет, которым собираемся отрисовывать линию. */

[[UIColor brownColor] set];


/* Получаем актуальный графический контекст. */

CGContextRef currentContext = UIGraphicsGetCurrentContext();


/* Задаем толщину линии. */

CGContextSetLineWidth(currentContext,

5.0f);


/* В этой точке будет начинаться линия. */

CGContextMoveToPoint(currentContext,

50.0f,

10.0f);


/* В этой точке линия будет заканчиваться. */

CGContextAddLineToPoint(currentContext,

100.0f,

200.0f);


/* Для отрисовки линии используем цвет, заданный в контексте в настоящий

момент. */

CGContextStrokePath(currentContext);


}


Запустив этот код в симуляторе iOS, вы получите примерно такие результаты, как на рис. 17.17.


Рис. 17.17. Рисование линии в текущем графическом контексте


Приведу еще один пример. Как было упомянуто ранее, процедура CGContextAddLineToPoint указывает конечную точку данной линии. А что делать, если мы уже провели линию из точки (20; 20) в точку (100; 100), а теперь хотим провести линию из точки (100; 100) в точку (300; 100)? Может возникнуть версия, что, нарисовав первую линию, мы должны переместить перо в точку (100; 100) с помощью процедуры CGContextMoveToPoint, а потом провести линию в точку (300; 100), используя процедуру CGContextAddLineToPoint. Да, это сработает, но задачу можно решить более эффективным способом. После того как вы вызовете процедуру CGContextAddLineToPoint для указания конечной точки отрисовываемой в данный момент линии, положение вашего пера изменится на значение, которое будет передано этому методу. Иными словами, после того, как вы выпустите метод, воспользовавшись пером, метод поставит перо в конечной точке того объекта, который был отрисован (объект может быть любым). Итак, чтобы нарисовать еще одну линию из актуальной конечной точки в новую точку, нужно просто еще раз вызвать процедуру CGContextAddLineToPoint, сообщив ей новую конечную точку. Вот пример:


— (void)drawRect:(CGRect)rect{


/* Задаем цвет, которым мы собираемся отрисовывать линию. */

[[UIColor brownColor] set];


/* Получаем актуальный графический контекст. */

CGContextRef currentContext = UIGraphicsGetCurrentContext();


/* Задаем толщину линий. */

CGContextSetLineWidth(currentContext,

5.0f);


/* В этой точке будет начинаться линия. */

CGContextMoveToPoint(currentContext,

20.0f,

20.0f);


/* В этой точке линия будет заканчиваться. */

CGContextAddLineToPoint(currentContext,

100.0f,

100.0f);


/* Продолжаем линию до новой точки. */

CGContextAddLineToPoint(currentContext,

300.0f,

100.0f);


/* Для отрисовки линии используем цвет, заданный в контексте в настоящий

момент. */

CGContextStrokePath(currentContext);


}


Результат показан на рис. 17.18. Как видите, удалось успешно отрисовать обе линии, не перемещая перо для отрисовки второй линии.

Точка соединения двух линий называется перемычкой (Join). Работая с Core Graphics, можно указывать тип перемычки, которую вы хотите сделать между линиями, сочлененными друг с другом. Для выбора такого типа используется процедура CGContextSetLineJoin. Она принимает два параметра: во-первых, графический контекст, в котором вы задаете перемычку такого типа, а во-вторых, сам тип перемычки, CGLineJoin. CGLineJoin — это перечень следующих значений:


Рис. 17.18. Одновременно отрисовываем две линии


• kCGLineJoinMiter — на месте перемычки образуется острый угол. Этот тип задается по умолчанию;

• kCGLineJoinBevel — угол на месте перемычки линий будет немного спрямлен, как будто обтесан;

• kCGLineJoinRound — как понятно из названия, такая перемычка — скругленная.


Рассмотрим пример. Допустим, мы хотим написать программу, способную отрисовывать в графическом контексте «скатные крыши», каждая из которых иллюстрировала бы определенный тип перемычки между линиями, а также выводить под «крышей» текст с названием используемой перемычки. В результате получится рисунок, напоминающий рис. 17.19.


Рис. 17.19. Три типа перемычек между линиями, существующие в Core Graphics


Для решения этой задачи я написал метод drawRooftopAtTopPointof: textToDisplay: lineJoin:, принимающий три параметра:

• точку, в которой должна располагаться верхушка «крыши»;

• текст, отображаемый под «крышей»;

• используемый тип перемычки.


Код будет таким:


— (void) drawRooftopAtTopPointof:(CGPoint)paramTopPoint

textToDisplay:(NSString *)paramText

lineJoin:(CGLineJoin)paramLineJoin{


/* Задаем цвет, которым собираемся отрисовывать линию. */

[[UIColor brownColor] set];


/* Получаем актуальный графический контекст. */

CGContextRef currentContext = UIGraphicsGetCurrentContext();


/* Задаем перемычку между линиями. */

CGContextSetLineJoin(currentContext,

paramLineJoin);


/* Задаем толщину линий. */

CGContextSetLineWidth(currentContext,

20.0f);


/* В этой точке будет начинаться линия. */

CGContextMoveToPoint(currentContext,

paramTopPoint.x — 140,

paramTopPoint.y + 100);


/* В этой точке линия будет заканчиваться. */

CGContextAddLineToPoint(currentContext,

paramTopPoint.x,

paramTopPoint.y);


/* Продолжаем линию до новой точки, чтобы получилась фигура,

напоминающая крышу. */

CGContextAddLineToPoint(currentContext,

paramTopPoint.x + 140,

paramTopPoint.y + 100);


/* Для отрисовки линии используем цвет, заданный в контексте в настоящий

момент. */

CGContextStrokePath(currentContext);


/* Рисуем под крышей текст, при этом используется черный цвет. */

[[UIColor blackColor] set];


/* Теперь рисуем текст. */

CGPoint drawingPoint = CGPointMake(paramTopPoint.x — 40.0f,

paramTopPoint.y + 60.0f);

[paramText drawAtPoint: drawingPoint

withFont: [UIFont boldSystemFontOfSize:30.0f]];


}

А теперь вызовем наш метод в методе экземпляра drawRect: объекта-вида, где находится графический контекст:

— (void)drawRect:(CGRect)rect{


[self drawRooftopAtTopPointof: CGPointMake(160.0f, 40.0f)

textToDisplay:@"Miter"

lineJoin: kCGLineJoinMiter];


[self drawRooftopAtTopPointof: CGPointMake(160.0f, 180.0f)

textToDisplay:@"Bevel"

lineJoin: kCGLineJoinBevel];


[self drawRooftopAtTopPointof: CGPointMake(160.0f, 320.0f)

textToDisplay:@"Round"

lineJoin: kCGLineJoinRound];

}

См. также

Разделы 17.3 и 17.7.

17.7. Создание путей