Рисование форм Используя пути Bézier
В iOS 3.2 и позже, можно использовать UIBezierPath
класс для создания основанных на векторе путей. UIBezierPath
класс является оберткой Objective C для связанных с путем функций в Базовой Графической платформе. Можно использовать этот класс для определения простых форм, таких как овалы и прямоугольники, а также сложные формы, включающие многократные прямые и изогнутые сегменты линии.
Можно использовать объекты контуров для рисования форм в пользовательском интерфейсе приложения. Можно нарисовать схему пути, заполнить пространство, которое она включает, или оба. Можно также использовать пути для определения области отсечения для текущего графического контекста, который можно тогда использовать для изменения последующих операций рисования в том контексте.
Основы пути Bézier
A UIBezierPath
объект является оберткой для a CGPathRef
тип данных. Пути являются основанными на векторе формами, создающимися с помощью линейных сегментов и сегментов кривой. Можно использовать линейные сегменты для создания прямоугольников и многоугольников, и можно использовать сегменты кривой, чтобы создать дуги, круги, и объединить искривленные формы. Каждый сегмент состоит из одной или более точек (в текущей системе координат) и команда рисования, определяющая, как интерпретируются те точки.
Каждый набор связанной строки и сегментов кривой формирует то, что упоминается как подпуть. Конец одного линейного сегмента или сегмента кривой по подпути определяет начало следующего. Сингл UIBezierPath
объект может содержать один или несколько подпутей, определяющих полный путь, разделенный moveToPoint:
команды, эффективно повышающие рейсфедер и перемещающие его в новое расположение.
Процессы для создания и использования объекта контуров являются отдельными. Создание пути является первым процессом и включает следующие шаги:
Создайте объект контуров.
Установите любые соответствующие атрибуты получения Вашего
UIBezierPath
объект, такой какlineWidth
илиlineJoinStyle
свойства для перечеркиваемых путей илиusesEvenOddFillRule
свойство для заполненных путей. Эти атрибуты получения применяются ко всему пути.Установите начальную точку начального сегмента с помощью
moveToPoint:
метод.Добавьте линейные сегменты и сегменты кривой для определения подпути.
Дополнительно, закройте подпуть путем вызова
closePath
, который рисует сегмент прямой линии из конца последнего сегмента к началу первого.Дополнительно, повторите шаги 3, 4, и 5 для определения дополнительных подпутей.
При создании пути необходимо расположить точки пути относительно точки источника (0, 0). Выполнение так упрощает перемещать путь позже. Во время получения точки Вашего пути применяются как есть к системе координат текущего графического контекста. Если Ваш путь ориентирован относительно источника, все, что необходимо сделать, чтобы изменить местоположение его, применяют аффинное преобразование с фактором перевода к текущему графическому контексту. Преимущество изменения графического контекста (в противоположность самому объекту контуров) состоит в том, что можно легко отменить трансформацию путем сохранения и восстановления состояния графики.
Для рисования объекта контуров Вы используете stroke
и fill
методы. Эти методы представляют линейные сегменты и сегменты кривой Вашего пути в текущем графическом контексте. Процесс рендеринга включает растеризацию линейных сегментов и сегментов кривой с помощью атрибутов объекта контуров. Процесс растеризации не изменяет сам объект контуров. В результате можно представить тот же объект контуров многократно в текущем контексте или в другом контексте.
Добавление строк и многоугольников к пути
Строки и многоугольники являются простыми формами, что Вы создаете детально использование moveToPoint:
и addLineToPoint:
методы. moveToPoint:
метод устанавливает начальную точку формы, которую Вы хотите создать. От той точки Вы создаете строки формы с помощью addLineToPoint:
метод. Вы создаете строки по очереди с каждой строкой, сформированной между предыдущей точкой и новой точкой, которую Вы указываете.
Перечисление 2-1 показывает, что код должен был создать пятигранную форму с помощью отдельных линейных сегментов. (Рисунок 2-1 показывает результат рисования этой формы с надлежащими настройками цвета обводки и цвета заливки, как описано в Рендеринге Содержания Объекта контуров Bézier.) Это кодовые наборы начальная точка формы и затем добавляет четыре связанных линейных сегмента. Пятый сегмент добавляется вызовом к closePath
метод, соединяющий последнюю точку (0, 40) с первой точкой (100, 0).
Перечисление 2-1 , Создающее пятигранную форму
UIBezierPath *aPath = [UIBezierPath bezierPath]; |
// Set the starting point of the shape. |
[aPath moveToPoint:CGPointMake(100.0, 0.0)]; |
// Draw the lines. |
[aPath addLineToPoint:CGPointMake(200.0, 40.0)]; |
[aPath addLineToPoint:CGPointMake(160, 140)]; |
[aPath addLineToPoint:CGPointMake(40.0, 140)]; |
[aPath addLineToPoint:CGPointMake(0.0, 40.0)]; |
[aPath closePath]; |
Используя closePath
метод не только заканчивает подпуть, описывающий форму, это также чертит линию сегмент между первыми и последними точками. Это - удобный способ закончить многоугольник, не имея необходимость проводить заключительную линию.
Добавление дуг к пути
UIBezierPath
класс предоставляет поддержку для инициализации нового объекта контуров с сегментом дуги. Параметры bezierPathWithArcCenter:radius:startAngle:endAngle:clockwise:
метод определяет круг, содержащий желаемую дугу и запуск и конечные точки самой дуги. Рисунок 2-2 показывает компоненты, входящие в создание дуги, включая круг, определяющий дугу, и угловые измерения раньше указывали его. В этом случае дуга создается в направлении по часовой стрелке. (Рисование дуги в направлении против часовой стрелки нарисовало бы штриховую часть круга вместо этого.) Код для создания этой дуги показан в Перечислении 2-2.
Перечисление 2-2 , Создающее новый путь дуги
// pi is approximately equal to 3.14159265359. |
#define DEGREES_TO_RADIANS(degrees) ((pi * degrees)/ 180) |
- (UIBezierPath *)createArcPath |
{ |
UIBezierPath *aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) |
radius:75 |
startAngle:0 |
endAngle:DEGREES_TO_RADIANS(135) |
clockwise:YES]; |
return aPath; |
} |
Если Вы хотите включить сегмент дуги в середину пути, необходимо изменить объект контуров CGPathRef
тип данных непосредственно. Для получения дополнительной информации об изменении пути с помощью Базовых Графических функций, посмотрите Изменение Пути Используя Базовые Графические Функции.
Добавление кривых к пути
UIBezierPath
класс предоставляет поддержку для добавления кубических и квадратичных кривых Bézier к пути. Сегменты кривой запускаются в текущей точке и конце в точке, которую Вы указываете. Форма кривой определяется с помощью строк касательной между запуском и конечными точками и одной или более контрольными точками. Рисунок 2-3 показывает приближения обоих типов кривой и отношения между контрольными точками и формой кривой. Точное искривление каждого сегмента включает сложное математическое отношение между всеми точками и хорошо документируется онлайн и в Википедии.
Для добавления кривых к пути Вы используете следующие методы:
Кубическая кривая:
addCurveToPoint:controlPoint1:controlPoint2:
Квадратичная кривая:
addQuadCurveToPoint:controlPoint:
Поскольку кривые полагаются на текущую точку пути, необходимо установить текущую точку прежде, чем вызвать любой из предыдущих методов. После завершения кривой текущая точка обновляется к новой конечной точке, которую Вы указали.
Создание овальных и прямоугольных контуров
Овалы и прямоугольники являются общими типами путей, создающихся с помощью комбинации кривой и линейных сегментов. UIBezierPath
класс включает bezierPathWithRect:
и bezierPathWithOvalInRect:
удобные методы для создания путей с овальными или прямоугольными формами. Оба из этих методов создают новый объект контуров и инициализируют его с указанной формой. Можно использовать возвращенный объект контуров сразу же или добавить больше форм к нему по мере необходимости.
Если Вы хотите добавить прямоугольник к существующему объекту контуров, необходимо сделать настолько использующий moveToPoint:
, addLineToPoint:
, и closePath
методы, как Вы были бы для любого другого многоугольника. Используя closePath
метод для заключительной стороны прямоугольника является удобным способом добавить заключительную строку пути и также отметить конец прямоугольного подпути.
Если Вы хотите добавить овал к существующему пути, самый простой способ сделать так состоит в том, чтобы использовать Базовую Графику. Несмотря на то, что можно использовать addQuadCurveToPoint:controlPoint:
приблизить овальную поверхность, CGPathAddEllipseInRect
функция намного более проста использовать и более точный. Для получения дополнительной информации посмотрите Изменение Пути Используя Базовые Графические Функции.
Изменение пути Используя базовые графические функции
UIBezierPath
класс является действительно просто оберткой для a CGPathRef
тип данных и атрибуты получения связались с тем путем. Несмотря на то, что Вы обычно добавляете линейные сегменты и сегменты кривой с помощью методов UIBezierPath
класс, класс также представляет a CGPath
свойство то, что можно использовать для изменения базового типа данных пути непосредственно. Когда Вы предпочли бы создавать свой путь с помощью функций Базовой Графической платформы, можно использовать это свойство.
Существует два способа изменить путь, связанный с a UIBezierPath
объект. Можно изменить путь полностью с помощью Базовых Графических функций, или можно использовать смесь Базовых Графических функций и UIBezierPath
методы. Изменение пути полностью с помощью Базовых Графических вызовов проще до некоторой степени. Вы создаете непостоянное CGPathRef
тип данных и вызывает любые функции, необходимо изменить его информацию о пути. Когда Вы сделаны, Вы присваиваете свой объект контуров соответствию UIBezierPath
объект, как показано в Перечислении 2-3.
Перечисление 2-3 , Присваивающее новое CGPathRef
к a UIBezierPath
объект
// Create the path data. |
CGMutablePathRef cgPath = CGPathCreateMutable(); |
CGPathAddEllipseInRect(cgPath, NULL, CGRectMake(0, 0, 300, 300)); |
CGPathAddEllipseInRect(cgPath, NULL, CGRectMake(50, 50, 200, 200)); |
// Now create the UIBezierPath object. |
UIBezierPath *aPath = [UIBezierPath bezierPath]; |
aPath.CGPath = cgPath; |
aPath.usesEvenOddFillRule = YES; |
// After assigning it to the UIBezierPath object, you can release |
// your CGPathRef data type safely. |
CGPathRelease(cgPath); |
Если Вы принимаете решение использовать смесь Базовых функций Графики и UIBezierPath
методы, необходимо тщательно переместить информацию о пути назад и вперед между двумя. Поскольку a UIBezierPath
объекту принадлежит его базовое CGPathRef
тип данных, Вы не можете просто получить тот тип и изменить его непосредственно. Вместо этого необходимо сделать непостоянную копию, изменить копию, и затем присвоить копию назад CGPath
свойство как показано в Перечислении 2-4.
Перечисление 2-4 , смешивающее базовую графику и UIBezierPath
вызовы
UIBezierPath *aPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 300, 300)]; |
// Get the CGPathRef and create a mutable version. |
CGPathRef cgPath = aPath.CGPath; |
CGMutablePathRef mutablePath = CGPathCreateMutableCopy(cgPath); |
// Modify the path and assign it back to the UIBezierPath object. |
CGPathAddEllipseInRect(mutablePath, NULL, CGRectMake(50, 50, 200, 200)); |
aPath.CGPath = mutablePath; |
// Release both the mutable copy of the path. |
CGPathRelease(mutablePath); |
Рендеринг содержания объекта контуров Bézier
После создания a UIBezierPath
объект, можно представить его в текущем графическом контексте с помощью stroke
и fill
методы. Перед вызовом этих методов, тем не менее, обычно существует несколько других задач выполнить, чтобы гарантировать, что путь нарисован правильно:
Выберите желаемые цвета обводки и цвета заливки с помощью методов
UIColor
класс.Расположите форму, где Вы хотите ее в целевом представлении.
При создании пути относительно точки (0, 0), можно применить надлежащее аффинное преобразование к текущему контексту получения. Например, для рисования формы, запускающейся в точке (10, 10), Вы вызвали бы
CGContextTranslateCTM
функционируйте и укажите10
и для горизонтальных и для вертикальных значений перевода. Корректировка графического контекста (в противоположность точкам в объекте контуров) предпочтена, потому что можно отменить изменение более легко путем сохранения и восстановления предыдущего состояния графики.Обновите атрибуты получения объекта контуров. Атрибуты получения Вашего
UIBezierPath
переопределение экземпляра значения связалось с графическим контекстом при рендеринге пути.
Перечисление 2-5 показывает демонстрационную реализацию a drawRect:
метод, рисующий овал в пользовательском представлении. Верхний левый угол ограничительного прямоугольника овала расположен в точке (50, 50) в системе координат представления. Поскольку операции заполнения красят прямо до границы пути, этот метод заполняет путь прежде, чем перечеркнуть ее. Это препятствует тому, чтобы цвет заливки затенил половину перечеркиваемой строки.
Перечисление 2-5 , Получающее путь в представлении
- (void)drawRect:(CGRect)rect |
{ |
// Create an oval shape to draw. |
UIBezierPath *aPath = [UIBezierPath bezierPathWithOvalInRect: |
CGRectMake(0, 0, 200, 100)]; |
// Set the render colors. |
[[UIColor blackColor] setStroke]; |
[[UIColor redColor] setFill]; |
CGContextRef aRef = UIGraphicsGetCurrentContext(); |
// If you have content to draw after the shape, |
// save the current state before changing the transform. |
//CGContextSaveGState(aRef); |
// Adjust the view's origin temporarily. The oval is |
// now drawn relative to the new origin point. |
CGContextTranslateCTM(aRef, 50, 50); |
// Adjust the drawing options as needed. |
aPath.lineWidth = 5; |
// Fill the path before stroking it so that the fill |
// color does not obscure the stroked line. |
[aPath fill]; |
[aPath stroke]; |
// Restore the graphics state before drawing any other content. |
//CGContextRestoreGState(aRef); |
} |
Выполнение обнаружения хита на пути
Чтобы определить, имело ли сенсорное событие место на заполненной части пути, можно использовать containsPoint:
метод UIBezierPath
. Этот метод тестирует указанную точку против всех закрытых подпутей в объекте контуров и возвратах YES
если это находится на или в каком-либо из тех подпутей.
Если Вы хотите сделать тестирование хита на перечеркиваемой части пути (вместо закрашенной области), необходимо использовать Базовую Графику. CGContextPathContainsPoint
функция позволяет Вам контрольные точки или на заливке или на штриховой части пути, в настоящее время присваиваемого графическому контексту. Перечисление 2-6 показывает метод, тестирующий, чтобы видеть, пересекает ли указанная точка указанный путь. Параметр заполнения позволяет вызывающей стороне указать, должна ли точка быть протестирована против заполненной или перечеркиваемой части пути. Путь, переданный в вызывающей стороной, должен содержать один или несколько закрытые подпути для обнаружения хита для следования.
Перечисление 2-6 , Тестирующее точки против объекта контуров
- (BOOL)containsPoint:(CGPoint)point onPath:(UIBezierPath *)path inFillArea:(BOOL)inFill |
{ |
CGContextRef context = UIGraphicsGetCurrentContext(); |
CGPathRef cgPath = path.CGPath; |
BOOL isHit = NO; |
// Determine the drawing mode to use. Default to |
// detecting hits on the stroked portion of the path. |
CGPathDrawingMode mode = kCGPathStroke; |
if (inFill) |
{ |
// Look for hits in the fill area of the path instead. |
if (path.usesEvenOddFillRule) |
mode = kCGPathEOFill; |
else |
mode = kCGPathFill; |
} |
// Save the graphics state so that the path can be |
// removed later. |
CGContextSaveGState(context); |
CGContextAddPath(context, cgPath); |
// Do the hit detection. |
isHit = CGContextPathContainsPoint(context, point, mode); |
CGContextRestoreGState(context); |
return isHit; |
} |