Что такое кварц 2D?
Quartz 2D — это движок рисования 2D Apple, важный компонент инфраструктуры Core Graphics. Вы можете часто видеть Quartz 2D, называемый Core Graphics или просто CG.
Кварц 2D использует «модель художника». В модели художника каждая последующая операция рисования применяет слой «краски» к выходному «холсту», часто называемому страницей. Думайте об этом как о художнике, работающем над картиной. Если бы художник нарисовал весь холст синим цветом, а затем нарисовал несколько облаков на холсте, то облака покрыли бы синий цвет под ними. Как только что-то «нарисовано» на холсте, оно не может быть изменено, но добавляя больше краски поверх него.
Все рисование в Quartz 2D выполняется через графический контекст типа CGContextRef . Со ссылкой на графический контекст вы можете использовать 2D-функции Quartz для рисования в контексте, выполнения операций, таких как перевод контекста, и изменения параметров графического состояния, таких как ширина линии и цвет заливки. Quartz 2D — это API на основе C, поэтому вы будете вызывать функции C, передаваемые в контексте, в качестве параметра.
Чтобы рисовать на экране в iOS, вы должны создать подкласс UIView и переопределить его метод drawRect(_:) . Именно внутри этого метода drawRect(_:) вы будете выполнять любой пользовательский рисунок. Вы никогда не должны вызывать метод drawRect(_:) прямо в вашем коде. Если вам нужно обновить экран новыми командами рисования, вам следует вызвать методы setNeedsDisplay() или setNeedsDisplayInRect(_:) .
При использовании Quartz 2D на iOS координата (0,0) находится в левом верхнем углу экрана. Координата x увеличивается при движении вправо, а координата y увеличивается при движении вниз.
В этом руководстве вы можете обратиться к руководству по программированию Quartz 2D. Цель этого урока — начать использовать Quartz 2D. Существует многое, что не будет рассмотрено, и чтобы полностью оценить все, что может предложить Quartz 2D, я предлагаю вам прочитать руководство по программированию.
С этим кратким введением давайте начнем использовать Quartz 2D.
1. Подготовка UIView для рисования
Предполагая, что у вас есть открытый проект и вы готовы начать работу с Quartz 2D, шаги, которые вам нужно сделать, довольно просты. Вам нужно будет создать класс, который является подклассом UIView , добавить представление из библиотеки объектов в проект в Interface Builder и установить класс этого представления в UIView вами подкласс UIView . Давайте пройдем этот шаг за шагом.
Шаг 1: UIView подклассов UIView
Перейдите в Файл > Создать > Файл …. В разделе iOS выберите Source, а затем выберите Cocoa Touch Class в качестве шаблона.

На следующем экране UIView своему классу имя, убедитесь, что это подкласс UIView , и установите для языка значение Swift . Нажмите Далее и выберите, где сохранить новый класс.

Если вы просмотрите исходный код только что созданного вами класса, вы увидите метод drawRect(_:) . В настоящее время это закомментировано, но мы изменим это через несколько минут.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
import UIKit
class DrawLineView: UIView {
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
}
|
Шаг 2. Добавление представления и настройка класса.
Откройте раскадровку проекта и откройте библиотеку объектов справа. В поле поиска внизу введите « UIView », чтобы отфильтровать объекты, которые нам не интересны.

Перетащите экземпляр UIView на контроллер представления. С выбранным видом, откройте Identity Inspector справа и измените Class на тот, который вы назвали подклассом.

Любой код, который вы добавляете в метод drawRect(_:) будет нарисован, когда будет создан UIView подкласса UIView . Вид автоматически настраивает среду рисования, чтобы вы могли немедленно начать рисование. Представление настраивает CGContextRef упомянутый в начале этого урока, и внутри метода drawRect(_:) вы получите ссылку на него.
2. Стартовый проект
Чтобы быстро начать работу, я предоставил стартовый проект, в котором все виды уже подключены и готовы к использованию. Подклассы UIView названы в честь команды рисования, которую мы будем изучать. Например, когда мы учимся рисовать линии, соответствующий класс будет называться DrawLinesView .
Вы можете скачать стартовый проект с GitHub . Мы начнем кодирование на следующем шаге.
3. Получение ссылки на графический контекст
Прежде чем вы сможете сделать любой рисунок, вам нужно получить ссылку на графический контекст. Это достигается следующим образом.
|
1
|
let context = UIGraphicsGetCurrentContext()
|
Это возвращает непрозрачный тип, CGContextRef , и вы передадите этот context в функции C для выполнения пользовательского рисования. Теперь, когда мы знаем, как получить ссылку на графический контекст, мы можем начать исследовать команды рисования.
4. Рисование линии
Если вы загрузили начальный проект, откройте DrawLineView.swift и добавьте следующее в метод drawRect(_:) .
|
1
2
3
4
5
6
7
|
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
CGContextSetStrokeColorWithColor(context, UIColor.redColor().CGColor)
CGContextMoveToPoint(context, 0, 0)
CGContextAddLineToPoint(context, 200, 200)
CGContextStrokePath(context)
}
|
Сначала мы получаем ссылку на контекст рисования, как обсуждалось ранее. Поскольку это то, что мы будем делать для каждого примера, я не буду упоминать это в следующих примерах.
Функция CGContextSetStrokeColorWithColor(_:_:) устанавливает цвет, с помощью которого линия будет нарисована или обведена. Параметры, которые мы передаем, — это графический контекст и новый цвет обводки.
Если вы рассматриваете графический контекст как холст художника, то CGContextMoveToPoint(_:_:_:) перемещает кисть в определенную точку холста, с которой начинается или продолжается рисование. Представьте, что вы рисуете на листе бумаги, поднимаете руку, переходите к другой части листа и продолжаете рисовать. По сути, это то, что этот метод выполняет. Мы передаем графический контекст и координаты x и y, чтобы начать рисование.
Функция CGContextAddLineToPoint(_:_:_:) принимает в качестве параметров графический контекст, значение x для конца сегмента линии и значение y для конца сегмента линии. После добавления линейного сегмента текущая точка будет установлена в конечную точку линейного сегмента. Мы начали операцию рисования в (0,0), после этой операции рисования курсор или кисть в (200,200).
Наконец, чтобы сделать фактическое рисование, вам нужно вызвать CGContextStrokePath(_:) передающую в графическом CGContextStrokePath(_:) функция просто рисует линию вдоль указанного нами пути.
Создайте и запустите пример проекта, чтобы увидеть эффект.
5. Рисование прямоугольника
Откройте DrawRectangleView.swift и добавьте следующее в метод drawRect(_:) . Вы должны быть знакомы с первыми двумя строками.
|
1
2
3
4
5
6
7
|
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
CGContextSetStrokeColorWithColor(context,UIColor.redColor().CGColor)
let rectangle = CGRectMake(50,50,frame.size.width-100,frame.size.height-100)
CGContextAddRect(context,rectangle)
CGContextStrokePath(context)
}
|
Функция CGRectMake(_:_:_:_:) является частью CGGeometry и предоставляет простой способ создания структуры CGRect . Как следует из названия, CGRect — это структура, которая содержит расположение и размеры прямоугольника. CGRect имеет два поля, origin и size , которые являются CGPoint и CGSize соответственно. Если вы не знакомы с этими типами данных, быстро ознакомьтесь со справочником CGGeometry .
Мы создаем константу, rectangle , используя CGRectMake(_:_:_:_:) и вызываем функцию CGContextAddRect(_:_:) , которая принимает в качестве параметров графический контекст и CGRect . Наконец, мы вызываем CGContextStrokePath(context) для рисования прямоугольника.
Создайте и запустите проект, чтобы увидеть прямоугольник, нарисованный на экране.
6. Рисование круга
Откройте DrawCircleView.swift и обновите метод drawRect(_:) следующим образом.
|
1
2
3
4
5
6
7
|
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
CGContextSetStrokeColorWithColor(context,UIColor.redColor().CGColor)
let rectangle = CGRectMake(50,50,frame.size.width-100,frame.size.height-100)
CGContextAddEllipseInRect(context,rectangle)
CGContextStrokePath(context)
}
|
Возможно, вам интересно, почему мы вызываем CGRectMake(_:_:_:_:) когда рисуем круг? Прямоугольник — это область, в которую должен поместиться круг. В приведенном выше коде мы создаем круг с помощью квадрата. Если вы хотите нарисовать овал или эллипс, то вам нужно сделать прямоугольник более прямоугольной формы.
Затем мы вызываем CGContextAddEllipseInRect(_:_:) , которая принимает в качестве параметров графический контекст и прямоугольник для рисования эллипса. Круг рисуется путем вызова CGContextStrokePath(_:) , передавая в графическом контексте.
7. Рисование дуги
Откройте DrawArcView.swift и добавьте следующий код в метод drawRect(_:) .
|
1
2
3
4
5
6
|
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
CGContextSetStrokeColorWithColor(context,UIColor.redColor().CGColor)
CGContextAddArc(context, 100,100,50,3.14,0,1)
CGContextStrokePath(context)
}
|
Функция CGContextAddArc(_:_:_:_:_:_:_:) принимает довольно много параметров:
- графический контекст
- значение х для центра дуги
- значение у для центра дуги
- радиус дуги
- угол к начальной точке дуги, измеренный в радианах от положительной оси х
- угол к конечной точке дуги, измеренный в радианах от положительной оси х
- значение 1 для создания дуги по часовой стрелке или значение 0 для создания дуги против часовой стрелки
8. Рисование Пути
Чтобы нарисовать более сложные фигуры, вы создаете контур и обводите его. Взгляните на метод drawRect(_:) в DrawPathView.swift.
|
1
2
3
4
5
6
7
8
9
|
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
CGContextSetStrokeColorWithColor(context, UIColor.redColor().CGColor)
CGContextMoveToPoint(context, 25, 150)
CGContextAddLineToPoint(context, 175, 150)
CGContextAddLineToPoint(context, 100, 50)
CGContextAddLineToPoint(context, 25, 150)
CGContextStrokePath(context)
}
|
В методе drawRect(_:) мы вызываем CGContextAddLineToPoint(_:_:_:) несколько раз, чтобы создать треугольник. Обратите внимание, что треугольник не заполнен, только штрих. На следующем шаге мы увидим, как заполнить треугольник цветом.
9. Заполнение пути
Откройте FillPathView.swift и обновите метод drawRect(_:) как показано ниже.
|
1
2
3
4
5
6
7
8
9
|
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
CGContextMoveToPoint(context, 25, 150)
CGContextAddLineToPoint(context, 175, 150)
CGContextAddLineToPoint(context, 100, 50)
CGContextAddLineToPoint(context, 25, 150)
CGContextSetFillColorWithColor(context,UIColor.redColor().CGColor)
CGContextFillPath(context)
}
|
На предыдущем шаге мы обводили путь, но вы также можете заполнить путь определенным цветом. В приведенном выше методе drawRect(_:) мы начинаем с создания пути для того же треугольника, что и в предыдущем примере. На этот раз мы устанавливаем цвет заливки, используя CGContextSetFillColorWithColor(_:_:) и вызываем CGContextFillPath(_:) вместо CGContextStrokePath(_:) .
10. Заполнение эллипса
Помимо заполнения путей, вы также можете заполнить эллипсы и прямоугольники. В этом примере мы будем заполнять эллипс. Заполнение прямоугольника, однако, очень похоже. Документация расскажет вам, как это делается. Обновите метод drawRect(_:) в FillEllipseView.swift, как показано ниже.
|
01
02
03
04
05
06
07
08
09
10
|
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
CGContextSetLineWidth(context, 8.0)
CGContextSetStrokeColorWithColor(context,UIColor.redColor().CGColor)
let rectangle = CGRectMake(50,50,frame.size.width-100,frame.size.height-100)
CGContextAddEllipseInRect(context, rectangle)
CGContextStrokePath(context)
CGContextSetFillColorWithColor(context,UIColor.greenColor().CGColor)
CGContextFillEllipseInRect(context, rectangle)
}
|
Большая часть этого кода должна быть уже знакома. Мы используем новую функцию CGContextSetLineWidth(_:_:) , чтобы установить ширину линии, и мы вызываем CGContextFillEllipseInRect(_:_:) чтобы заполнить эллипс. Эта функция принимает в качестве параметров графический контекст и прямоугольник для заполнения эллипса.
11. Добавление линий
Функция CGContextAddLines(_:_:_:) — это удобная функция, когда у вас есть несколько связанных отрезков прямой линии, которые вы хотите нарисовать. Здесь мы воссоздаем треугольник из предыдущих примеров, используя CGContextAddLines(_:_:_:) . Добавьте следующий код в AddLinesView.swift .
|
1
2
3
4
5
6
7
|
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
CGContextSetStrokeColorWithColor(context, UIColor.redColor().CGColor)
let lines = [CGPointMake(25,150),CGPointMake(175,150),CGPointMake(100,50),CGPointMake(25,150)]
CGContextAddLines(context,lines,4)
CGContextStrokePath(context)
}
|
Функция CGContextAddLines(_:_:_:) принимает в качестве параметров графический контекст, массив значений, которые задают начальную и конечную точки отрезков линии для рисования в CGPoint структур CGPoint , и количество элементов в массиве. Обратите внимание, что первая точка в массиве указывает начальную точку.
12. Рисование градиента
С Quartz 2D легко рисовать градиенты. Поддерживаются как линейные, так и радиальные градиенты. В этом примере мы нарисуем линейный градиент. Документация поможет вам, если вы заинтересованы в рисовании радиальных градиентов. Добавьте следующее в DrawGradientView.swift .
|
01
02
03
04
05
06
07
08
09
10
|
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
let colorspace = CGColorSpaceCreateDeviceRGB()
let colors = [UIColor.redColor().CGColor,UIColor.blueColor().CGColor]
let locations: [CGFloat] = [ 0.0, 0.5]
let gradient = CGGradientCreateWithColors(colorspace,colors,locations)
let startPoint = CGPointMake(0,0)
let endPoint = CGPointMake(200,200)
CGContextDrawLinearGradient(context, gradient,startPoint, endPoint, 0)
}
|
Функция CGContextDrawLinearGradient(_:_:_:_:_:) принимает в качестве параметров:
- графический контекст
-
CGGradientструктура - отправная точка
- конечная точка
- флаги опций, которые определяют, будет ли заливка расширена за начальную или конечную точку
Структура CGGradient определяет плавный переход между цветами по области. Он имеет цветовое пространство, два или более цветов и местоположение для каждого цвета. colorspace констант, colors и locations в приведенном выше примере представляют эти части, которые составляют CGGradient .
Чтобы нарисовать градиент, мы вызываем CGContextDrawLinearGradient(_:_:_:_:_:) , передавая в графическом контексте значения CGGradient , начальные и конечные значения и 0, чтобы указать, что заливка должна выходить за пределы начальной позиции. ,
13. Рисование тени
Тень — это изображение, нарисованное под графическим объектом и смещенное от него, так что тень имитирует эффект источника света, отбрасываемого на графический объект. — Кварц 2D Руководство по программированию
Для рисования теней можно использовать две функции: CGContextSetShadow(_:_:_:) и CGContextSetShadowWithColor(_:_:_:_:) . При использовании CGContextSetShadow(_:_:_:) все нарисованные объекты затеняются черным цветом с 1/3 альфа. Функция CGContextSetShadowWithColor(_:_:_:_: позволяет вам указать цвет тени.
Посмотрим, как это работает на практике. Добавьте следующее в SetShadowWithColor.swift .
|
01
02
03
04
05
06
07
08
09
10
11
|
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
CGContextSaveGState(context)
let shadowOffset = CGSizeMake(-15,20)
CGContextSetShadowWithColor(context,shadowOffset,3,UIColor.greenColor().CGColor)
CGContextSetStrokeColorWithColor(context,UIColor.redColor().CGColor)
let rectangle = CGRectMake(50,50,frame.size.width-100,frame.size.height-100)
CGContextAddRect(context, rectangle)
CGContextStrokePath(context)
CGContextRestoreGState(context)
}
|
При рисовании теней необходимо сохранить состояние графического контекста, внести необходимые изменения, а затем восстановить графическое состояние. Мы вызываем CGContextSaveGState(_:) чтобы сохранить текущее состояние графического контекста, указать смещение для shadow, shadowOffset и вызвать CGContextSetShadowWithColor(_:_:_:_:) . Эта функция принимает в качестве параметров:
- графический контекст
- смещение для тени
- количество размытия
- цвет тени
Остальная часть кода должна быть вам знакома. Наконец, мы восстанавливаем графический контекст, вызывая CGContextRestoreGState(_:) , передавая графический контекст.
14. Рисование счастливого лица
Я подумал, что было бы интересно закончить этот урок, нарисовав простое счастливое лицо, используя то, что мы узнали в этом уроке. Добавьте следующее в DrawHappyFaceView.swift .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
let face = CGRectMake(50,50,frame.size.width-100,frame.size.height-100)
CGContextAddEllipseInRect(context, face)
CGContextSetFillColorWithColor(context,UIColor.yellowColor().CGColor)
CGContextFillEllipseInRect(context, face)
let leftEye = CGRectMake(75,75,10,10)
CGContextSetFillColorWithColor(context,UIColor.blackColor().CGColor)
CGContextFillEllipseInRect(context, leftEye)
let rightEye = CGRectMake(115,75,10,10)
CGContextFillEllipseInRect(context, rightEye)
CGContextSetLineWidth(context, 3.0)
CGContextAddArc(context, 100,100,30,3.14,0,1)
CGContextStrokePath(context)
}
|
Реализация метода drawRect(_:) должна иметь смысл, и вы должны иметь счастливое лицо, нарисованное на экране.
Вывод
На этом урок заканчивается. Теперь у вас должно быть общее представление о том, как выполнять пользовательское рисование с использованием механизма рисования Quartz 2D. Я надеюсь, что вы узнали что-то полезное, прочитав этот учебник.