UIBezierPath — класа из UIKit-а која инкапсулира векторску путању за 2D графику у iOS-у. Она комбинује геометријски опис контуре са могућностима цртања, омогућавајући креирање линија, Безјеових кривих, лукова и правоугаоника. За разлику од CGPath-а, UIBezierPath садржи сопствене методе цртања директно у тренутном графичком контексту. Према Apple Developer Documentation, 2026, UIBezierPath подржава све стандардне операције Quartz 2D у објектно-оријентисаном омотачу.
Главно
UIBezierPath — класа UIKit фрејмворка, наследник NSObject-а која имплементира NSCopying, NSSecureCoding. Пружа високонивоски Objective-C/Swift API за изградњу и цртање векторских контура. Унутрашње, UIBezierPath чува референцу на CGPathRef — Core Graphics објекат, али додаје погодне методе за цртање, промену геометрије и управљање стиловима.
Главна предност UIBezierPath-а у односу на директно коришћење CGPath-а су уграђене методе цртања. Позив fill() или stroke() на инстанци UIBezierPath-а аутоматски конфигурише контекст и црта путању. Класа такође подржава својства lineWidth, lineCapStyle, lineJoinStyle, miterLimit и flatness, што омогућава управљање изгледом без засебног објекта за чување стилова.
UIBezierPath се користи у већини iOS апликација за прилагођено цртање унутар UIView-а: од једноставних икона до сложених анимираних графикона. Метод draw(_:) класе UIView је главно место где програмери креирају и цртају UIBezierPath. Класа је потпуно компатибилна са Core Animation-ом и може се користити за анимацију путање кроз CAShapeLayer и CABasicAnimation.
Метод move(to:) помера почетну тачку путање на задате координате без цртања. Ово је обавезни позив пре изградње било ког сегмента. addLine(to:) додаје прави сегмент од тренутне позиције до наведене тачке. За затварање контуре користи се метод close(), који повлачи линију од последње тачке до прве тачке последњег move(to:).
UIBezierPath пружа неколико погодних иницијализатора за готове облике. init(rect:) креира правоугаоник, init(roundedRect:cornerRadius:) — правоугаоник са заобљеним угловима. Параметар UIRectCorner омогућава заобљавање само одабраних углова, на пример topLeft и bottomRight, остављајући остале правим. Ово се широко користи за креирање прилагођених дугмади и картица.
init(ovalIn:) креира елипсу уписану у задати правоугаоник. Ако је правоугаоник квадрат, елипса постаје круг. init(roundedRect:byRoundingCorners:cornerRadii:) — најфлексибилнија варијанта, која омогућава постављање различитих радијуса за сваки угао. Овај иницијализатор се појавио у iOS 6 и остаје стандард за креирање заобљених контејнера.
let path = UIBezierPath()
path.move(to: CGPoint(x: 50, y: 50))
path.addLine(to: CGPoint(x: 200, y: 50))
path.addLine(to: CGPoint(x: 200, y: 150))
path.addLine(to: CGPoint(x: 125, y: 200))
path.addLine(to: CGPoint(x: 50, y: 150))
path.close()
addQuadCurve(to:controlPoint:) додаје квадратну Безјеову криву са једном контролном тачком. Овај тип криве се користи за једноставне плавне савије када је потребно минимизирати број прорачуна. Квадратна крива је увек парабола и гарантовано лежи унутар троугла формираног од почетне, контролне и крајње тачке.
addCurve(to:controlPoint1:controlPoint2:) додаје кубну Безјеову криву са две контролне тачке. Кубне криве се користе у свим савременим векторским уређивачима и TrueType фонтовима. Две контролне тачке дају више степени слободе за прецизно управљање обликом криве. Овај метод се препоручује за изградњу органских и сложених контура.
При изградњи кривих важно је поштовати принцип континуитета — глаткоћу криве у тачки спајања сегмената. За континуитет C1 (тангента) контролна тачка следеће криве мора лежати на истој правој линији са контролном тачком претходне. За континуитет C2 (кривина) потребно је сложеније усклађивање, које се аутоматски обезбеђује у CAShapeLayer-у при анимацији између два UIBezierPath-а са истим бројем контролних тачака.
| Метод | Тип | Контролних тачака | Степен |
|---|---|---|---|
| addQuadCurve | Квадратна Безјеова | 1 | 2 |
| addCurve | Кубна Безјеова | 2 | 3 |
| addArc | Лук | — | — |
addArc(withCenter:radius:startAngle:endAngle:clockwise:) додаје лук круга са задатим параметрима. Углови се наводе у радијанима у односу на центар круга. Нулти угао одговара смеру удесно (3 сата на бројчанику). Параметар clockwise одређује смер: true — у смеру казаљке на сату, false — супротно. Лукови су незаменљиви за кружне дијаграме, брзиномјере и интерактивне прстенове напретка.
За пун круг довољни су startAngle = 0 и endAngle = .pi * 2. За креирање сектора (као дела кружног дијаграма) користите addArc са накнадним addLine(to:) до центра и close(). UIBezierPath нема уграђени метод addCircle — круг се креира кроз init(ovalIn:) са квадратним правоугаоником или кроз addArc са пуним углом.
Метод addArc(withCenter:radius:startAngle:endAngle:clockwise:) аутоматски извршава move(to:) до почетне тачке лука ако се тренутна позиција не поклапа са њом. Ако је тренутна позиција другачија, између ње и почетка лука повлачи се права линија. Ово понашање се разликује од рада са Core Graphics-ом, где је потребан експлицитни move(to:) пре сваке нове контуре.
let center = CGPoint(x: 150, y: 150)
let slice = UIBezierPath()
slice.move(to: center)
slice.addArc(
withCenter: center,
radius: 100,
startAngle: 0,
endAngle: .pi * 0.75,
clockwise: true
)
slice.close()
fill() попуњава унутрашњу област путање тренутном бојом fillColor или бојом постављеном у графичком контексту кроз setFill(). За путање са самопресецањима правило попуњавања одређује својство usesEvenOddFillRule. Ако је true, користи се even-odd правило: тачка се сматра унутар облика ако зрак из ње пресеца контуру непаран број пута.
stroke() црта контуру путање са тренутним подешавањима lineWidth, lineCapStyle и lineJoinStyle. lineCapStyle одређује облик крајева отворених сегмената: .butt (прави рез), .round (полукружни), .square (квадратни са испустом). lineJoinStyle одређује облик углова спојева: .miter (оштар), .round (заобљен), .bevel (сечен).
За испрекидане линије користи се својство setLineDash(_:count:phase:). Оно прима низ дужина наизменичних цртица и празнина, број елемената и почетну фазу. Визуелизација испрекидане линије се изводи у фази растерезације путање — сложени обрасци не повећавају геометријску сложеност контуре. CAShapeLayer подржава анимацију својства strokeEnd за ефекат „цртања“ линије од почетка до краја.
override func draw(_ rect: CGRect) {
let path = UIBezierPath(ovalIn: CGRect(x: 50, y: 50, width: 200, height: 200))
UIColor.blue.setFill()
UIColor.black.setStroke()
path.lineWidth = 4
path.fill()
path.stroke()
}
Направимо прилагођени индикатор напретка у облику прстена помоћу UIBezierPath-а. Прстен се гради од два лука истог радијуса али различите боје исцртавања. Први лук је пун круг сиве боје (позадина), други је сегмент који приказује напредак. За анимацију се користе CAShapeLayer и CABasicAnimation.
class RingView: UIView {
private let progressLayer = CAShapeLayer()
override func layoutSubviews() {
super.layoutSubviews()
let center = CGPoint(x: bounds.midX, y: bounds.midY)
let radius = bounds.width * 0.4
let lineWidth: CGFloat = 12
let backgroundRing = UIBezierPath()
backgroundRing.addArc(withCenter: center, radius: radius,
startAngle: -.pi / 2, endAngle: .pi * 1.5, clockwise: true)
progressLayer.path = backgroundRing.cgPath
progressLayer.strokeColor = UIColor.systemBlue.cgColor
progressLayer.lineWidth = lineWidth
progressLayer.lineCap = .round
progressLayer.fillColor = UIColor.clear.cgColor
progressLayer.strokeEnd = 0
layer.addSublayer(progressLayer)
}
func animateProgress(to value: CGFloat) {
CABasicAnimation(keyPath: "strokeEnd").apply {
$0.toValue = value
$0.duration = 1.5
$0.timingFunction = CAMediaTimingFunction(name: .easeOut)
progressLayer.add($0, forKey: nil)
}
progressLayer.strokeEnd = value
}
}
У овом примеру UIBezierPath се користи за креирање кружне контуре, која се затим прослеђује CAShapeLayer-у кроз својство cgPath. Анимација strokeEnd од 0 до 1 визуелизује попуњавање прстена. Овакав приступ се користи у индикаторима учитавања, фитнес тракерима и виџетима напретка. Метод layoutSubviews гарантује поновну изградњу путање при промени димензија View-а.
lineCap = .round додаје заобљене крајеве лука, што даје индикатору уреднији изглед. Својство strokeEnd је анимирајуће својство CAShapeLayer-а које не захтева прецртавање целе контуре у сваком кадру. Анимација се изводи у потпуности на GPU-у кроз Core Animation, што обезбеђује 60 FPS без оптерећења CPU-а.
Често постављана питања
UIBezierPath — објектно-оријентисани омотач CGPath-а који садржи уграђене методе fill() и stroke(). CGPath је немодификовани C објекат Core Graphics-а који захтева експлицитно цртање кроз CGContext. UIBezierPath је погоднији за UIKit, CGPath је перформантнији за поновну употребу.
Користите init(roundedRect:byRoundingCorners:cornerRadii:) са параметром .topLeft и .topRight за roundedRect. Ово је једини метод UIBezierPath-а који омогућава селективно заобљавање углова без креирања сложене состављене путање.
Својство cgPath враћа непроменљиви CGPathRef који се може проследити CAShapeLayer-у или користити са различитим бојама и дебљинама. Модификације UIBezierPath-а (померање тачака) не утичу на раније добијени cgPath до експлицитног ажурирања.
Проверите usesEvenOddFillRule — ако контура има самопресецања, even-odd правило може оставити области непопуњеним. Поставите usesEvenOddFillRule = false за стандардно non-zero winding правило попуњавања.
Користите CABasicAnimation са кључном путањом “path” на CAShapeLayer-у. Оба стања путање морају садржати исти број сегмената и контролних тачака — у супротном анимација ће бити трзава или неће радити.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође