iOS. Приемы программирования Нахавандипур Вандад
/* В этой точке линия будет заканчиваться. */
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. Создание путей
Постановка задачи
Необходимо иметь возможность нарисовать в графическом контексте любой желаемый контур.
Решение
Создавайте и отрисовывайте пути.
Обсуждение
Если расположить рядом серию точек, они могут образовать фигуру. Серия фигур, составленных вместе, образует путь. Управлять путями в Core Graphics очень удобно. В разделе 17.6 мы опосредованно работали с путями, пользуясь функциями CGContext. Но в Core Graphics есть и такие функции, которые работают с путями напрямую. Вскоре мы с ними познакомимся.
Пути относятся к тому графическому контексту, в котором они нарисованы. У путей нет границ либо конкретных контуров, в отличие от фигур, рисуемых по ним. Однако у путей есть ограничивающие рамки. Не забывайте, что граница и ограничивающая рамка — не тождественные понятия. Границы — это пределы, в которых вы можете рисовать на холсте, а ограничивающая рамка пути — это наименьший прямоугольник, в котором содержатся все фигуры, точки и другие объекты, отрисованные по данному конкретному пути. Пути можно сравнить с марками, а графический контекст — с конвертом для письма. Всякий раз, когда вы решите послать открытку другу, конверты для нее будут одинаковыми, но может различаться количество марок, которые вы наклеите на конверт (в нашем случае могут различаться пути).
Когда вы закончите рисование на определенном пути, можно отрисовать этот путь в графическом контексте. Разработчики, которым доводилось заниматься программированием игр, знакомы с понятием буфера. Буфер отрисовывает закрепленные за ним сцены и в нужный момент сбрасывает это содержимое на экран. Пути — это, в сущности, буферы. Они напоминают невидимые границы, рисуемые на холсте.
Приступая к непосредственной работе с путями, начнем с создания самого пути. Метод, создающий путь, возвращает описатель, которым вы будете пользоваться всякий раз, когда решите нарисовать что-либо на этом пути. Описатель передается Core Graphics для справки. Создав путь, вы сможете добавить к нему различные линии, фигуры и точки и только потом отрисовать его. Путь можно либо заполнить определенным цветом заливки, либо отрисовать штрихами в графическом контексте. Вот методы, с которыми придется работать:
• CGPathCreateMutable (функция) — создает новый изменяемый путь типа CGMutablePathRef и возвращает его описатель. Как только мы закончим работу с этим путем, от него необходимо избавиться — об этом мы вскоре поговорим;
• CGPathMoveToPoint (процедура) — перемещает на путь актуальное положение пера. Перо оказывается в точке, заданной в параметре типа CGPoint;
• CGPathAddLineToPoint (процедура) — отрисовывает сегмент линии от актуальной позиции пера до указанной позиции (которая опять же указывается как значение типа CGPoint);
• CGContextAddPath (процедура) — добавляет заданный путь (на который указывает переданный здесь описатель) в графический контекст. Этот путь готов для рисования;
• CGContextDrawPath (процедура) — отрисовывает заданный путь в графическом контексте;
• CGPathRelease (процедура) — высвобождает память, выделенную для описателя пути;
• CGPathAddRect (процедура) — добавляет к пути прямоугольник. Границы прямоугольника указаны в структуре CGRect.
Существуют три важных рисовальных метода, выполнение которых можно задать процедуре CGContextDrawPath:
• kCGPathStroke — рисует линию (штрих), отмечающий границу или кромку пути. Штрих рисуется актуальным цветом, выбранным в данный момент;
• kCGPathFill — заполняет цветом заливки область, вокруг которой описан путь. Заливка выполняется в актуальном цвете, выбранном в данный момент;
• kCGPathFillStroke — комбинирует штрих и заливку. Для заполнения пути использует актуальный цвет заливки, а выбранный цвет штриха применяет для отрисовки пути. В следующем разделе будет рассмотрен пример использования этого метода.
Рассмотрим пример. Допустим, нам необходимо нарисовать голубую линию, идущую по экрану из верхнего левого угла в нижний правый, и другую линию, идущую из верхнего правого угла в левый нижний. Так мы нарисуем на экране большой крест, напоминающий букву «X».
В этом примере я удалил из приложения в симуляторе iOS статусную панель. Если вы не хотите с этим возиться, то можете сразу переходить к коду, приведенному далее. При наличии статусной панели результат выполнения кода будет лишь незначительно отличаться от того, что показано на моем скриншоте. Чтобы скрыть статусную панель, найдите в вашем проекте Xcode файл Info.plist и добавьте в этот файл ключ UIStatusBarHidden со значением YES (рис. 17.20). В таком случае сразу после открытия приложения статусная панель будет скрыта.
Рис. 17.20. Операция с файлом Info.plist, позволяющая скрыть статусную панель приложения iOS
— (void)drawRect:(CGRect)rect{
/* Создаем путь. */
CGMutablePathRef path = CGPathCreateMutable();
/* Каковы размеры экрана? Мы хотим, чтобы X растянулся на весь экран. */
CGRect screenBounds = [[UIScreen mainScreen] bounds];
/* Начинаем с верхнего левого угла. */
CGPathMoveToPoint(path,
NULL,
screenBounds.origin.x,
screenBounds.origin.y);
/* Проводим линию из верхнего левого в нижний правый угол экрана. */
CGPathAddLineToPoint(path,
NULL,
screenBounds.size.width,
screenBounds.size.height);
/* Начинаем другую линию из верхнего правого угла. */
CGPathMoveToPoint(path,
NULL,
screenBounds.size.width,
screenBounds.origin.y);
/* Проводим линию из верхнего правого в нижний левый угол. */
CGPathAddLineToPoint(path,
NULL,
screenBounds.origin.x,
screenBounds.size.height);
/* Получаем контекст, в котором должен быть отрисован путь. */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Добавляем путь к контексту, чтобы позже его можно было отрисовать. */
CGContextAddPath(currentContext,
path);
/* Задаем для штриха голубой цвет. */
[[UIColor blueColor] setStroke];
/* Отрисовываем путь этим цветом. */
CGContextDrawPath(currentContext,
kCGPathStroke);
/* Наконец, высвобождаем объект пути. */
CGPathRelease(path);
}
Параметр NULL, передаваемый таким процедурам, как CGPathMoveToPoint, представляет возможные преобразования, которые могут быть применены при отрисовке фигур и линий по заданному пути. Подробнее о преобразованиях рассказано в разделах 17.11–17.13.
Итак, нарисовать путь в графическом контексте очень просто. На самом деле следует всего лишь запомнить, как создать новый изменяемый путь (CGPathCreateMutable), добавить этот путь к вашему графическому контексту (CGContextAddPath) и отрисовать путь в графическом контексте (CGContextDrawPath). Запустив этот код, вы получите примерно такой результат, как на рис. 17.21.
Рис. 17.21. Рисование в графическом контексте с использованием путей
См. также
Разделы 17.6, 17.11–17.13.
17.8. Отрисовка прямоугольников
Постановка задачи
Требуется отрисовывать прямоугольники в графическом контексте.
Решение
Воспользуйтесь CGPathAddRect для добавления прямоугольника к пути, а потом отрисовывайте этот путь в графическом контексте.
Обсуждение
Как мы узнали из раздела 17.7, создавать и использовать пути довольно просто. Одна из процедур, которую Core Graphics позволяет использовать с путями, — CGPathAddRect. Она позволяет отрисовывать прямоугольники как части путей. Вот пример:
— (void)drawRect:(CGRect)rect{
/* Сначала создаем путь. Просто описатель пути. */
CGMutablePathRef path = CGPathCreateMutable();
/* Это границы прямоугольника. */
CGRect rectangle = CGRectMake(10.0f,
10.0f,
200.0f,
300.0f);
/* Добавляем прямоугольник к пути. */
CGPathAddRect(path,
NULL,
rectangle);
/* Получаем описатель текущего контекста. */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Добавляем путь к контексту. */
CGContextAddPath(currentContext,
path);
/* Задаем голубой в качестве цвета заливки. */
[[UIColor colorWithRed:0.20f
green:0.60f
blue:0.80f
alpha:1.0f] setFill];
/* Задаем для обводки коричневый цвет. */
[[UIColor brownColor] setStroke];
/* Задаем для ширины (обводки) значение 5. */
CGContextSetLineWidth(currentContext,
5.0f);
/* Проводим путь в контексте и применяем к нему заливку. */
CGContextDrawPath(currentContext,
kCGPathFillStroke);
/* Избавляемся от пути. */
CGPathRelease(path);
}
Здесь мы рисуем на пути прямоугольник, который впоследствии заполняем голубым цветом, а края прямоугольника отрисовываем коричневым. На рис. 17.22 показано, что мы увидим, запустив эту программу (конечно же, цвета на черно-белой иллюстрации не видны).
Если вы собираетесь отрисовать несколько прямоугольников, то можете передать массив объектов CGRect процедуре CGPathAddRects. Вот пример:
— (void)drawRect:(CGRect)rect{
/* Сначала создаем путь. Просто описатель пути. */
CGMutablePathRef path = CGPathCreateMutable();
/* Это границы первого прямоугольника. */
CGRect rectangle1 = CGRectMake(10.0f,
10.0f,
Рис. 17.22. Отрисовка прямоугольника с помощью путей
200.0f,
300.0f);
/* Это границы второго прямоугольника. */
CGRect rectangle2 = CGRectMake(40.0f,
100.0f,
90.0f,
300.0f);
/* Помещаем оба прямоугольника в массив. */
CGRect rectangles[2] = {
rectangle1, rectangle2
};
/* Добавляем прямоугольники к пути. */
CGPathAddRects(path,
NULL,
(const CGRect *)&rectangles,
2);
/* Получаем описатель текущего контекста. */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Добавляем путь к контексту. */
CGContextAddPath(currentContext,
path);
/* Задаем голубой в качестве цвета заливки. */
[[UIColor colorWithRed:0.20f
green:0.60f
blue:0.80f
alpha:1.0f] setFill];
/* Задаем для обводки черный цвет. */
[[UIColor blackColor] setStroke];
/* Задаем для ширины (обводки) значение. 5 */
CGContextSetLineWidth(currentContext,
5.0f);
/* Проводим путь в контексте и применяем к нему заливку. */
CGContextDrawPath(currentContext,
kCGPathFillStroke);
/* Избавляемся от пути. */
CGPathRelease(path);
}
На рис. 17.23 показано, как результат выполнения этого кода будет выглядеть в симуляторе iOS. Мы передаем процедуре CGPathAddRects следующие параметры (именно в таком порядке).
Рис. 17.23. Одновременная отрисовка нескольких прямоугольников
1. Описатель пути, к которому мы будем добавлять прямоугольники.
2. Преобразование (при его наличии), которое потребуется применить к прямоугольникам. (Подробнее о преобразованиях рассказано в разделах 17.11–17.13.)
3. Ссылку на массив CGRect, в котором содержатся прямоугольники.
4. Количество прямоугольников в массиве, который мы передали в предыдущем параметре. Исключительно важно передать именно столько прямоугольников, сколько содержится в вашем массиве, чтобы избежать непредвиденного поведения этой процедуры.
См. также
Разделы 17.7, 17.11–17.13.
17.9. Добавление теней к фигурам
Постановка задачи
Требуется применять тени к тем фигурам, которые вы отрисовываете в графическом контексте.
Решение
Воспользуйтесь процедурой CGContextSetShadow.