Статьи

Введение в Кварц 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.

Предполагая, что у вас есть открытый проект и вы готовы начать работу с Quartz 2D, шаги, которые вам нужно сделать, довольно просты. Вам нужно будет создать класс, который является подклассом UIView , добавить представление из библиотеки объектов в проект в Interface Builder и установить класс этого представления в 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
    }
    */
     
}

Откройте раскадровку проекта и откройте библиотеку объектов справа. В поле поиска внизу введите « UIView », чтобы отфильтровать объекты, которые нам не интересны.

Показать библиотеку объектов

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

Установить класс на вид

Любой код, который вы добавляете в метод drawRect(_:) будет нарисован, когда будет создан UIView подкласса UIView . Вид автоматически настраивает среду рисования, чтобы вы могли немедленно начать рисование. Представление настраивает CGContextRef упомянутый в начале этого урока, и внутри метода drawRect(_:) вы получите ссылку на него.

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

Вы можете скачать стартовый проект с GitHub . Мы начнем кодирование на следующем шаге.

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

1
let context = UIGraphicsGetCurrentContext()

Это возвращает непрозрачный тип, CGContextRef , и вы передадите этот context в функции C для выполнения пользовательского рисования. Теперь, когда мы знаем, как получить ссылку на графический контекст, мы можем начать исследовать команды рисования.

Если вы загрузили начальный проект, откройте 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(_:) функция просто рисует линию вдоль указанного нами пути.

Создайте и запустите пример проекта, чтобы увидеть эффект.

Откройте 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) для рисования прямоугольника.

Создайте и запустите проект, чтобы увидеть прямоугольник, нарисованный на экране.

Откройте 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(_:) , передавая в графическом контексте.

Откройте 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 для создания дуги против часовой стрелки

Чтобы нарисовать более сложные фигуры, вы создаете контур и обводите его. Взгляните на метод 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(_:_:_:) несколько раз, чтобы создать треугольник. Обратите внимание, что треугольник не заполнен, только штрих. На следующем шаге мы увидим, как заполнить треугольник цветом.

Откройте 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(_:) .

Помимо заполнения путей, вы также можете заполнить эллипсы и прямоугольники. В этом примере мы будем заполнять эллипс. Заполнение прямоугольника, однако, очень похоже. Документация расскажет вам, как это делается. Обновите метод 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(_:_:) чтобы заполнить эллипс. Эта функция принимает в качестве параметров графический контекст и прямоугольник для заполнения эллипса.

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

С 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, чтобы указать, что заливка должна выходить за пределы начальной позиции. ,

Тень — это изображение, нарисованное под графическим объектом и смещенное от него, так что тень имитирует эффект источника света, отбрасываемого на графический объект. Кварц 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(_:) , передавая графический контекст.

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