Что такое кварц 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. Я надеюсь, что вы узнали что-то полезное, прочитав этот учебник.