UIBezierPath: шта је то, методе цртања и како ради

Аутор: IT Sectr Објављено: 2026-07-21 Време читања: 8 мин

UIBezierPath — класа из UIKit-а која инкапсулира векторску путању за 2D графику у iOS-у. Она комбинује геометријски опис контуре са могућностима цртања, омогућавајући креирање линија, Безјеових кривих, лукова и правоугаоника. За разлику од CGPath-а, UIBezierPath садржи сопствене методе цртања директно у тренутном графичком контексту. Према Apple Developer Documentation, 2026, UIBezierPath подржава све стандардне операције Quartz 2D у објектно-оријентисаном омотачу.

Главно

  • UIBezierPath — објектно-оријентисани омотач CGPath-а за рад са векторским контурама у UIKit-у.
  • move(to:) и addLine(to:) задају праве сегменте путање.
  • addQuadCurve(to:controlPoint:) и addCurve(to:controlPoint1:controlPoint2:) граде Безјеове криве.
  • addArc(withCenter:radius:startAngle:endAngle:clockwise:) креира лукове и секторе.
  • fill и stroke — директно цртање путање у тренутном контексту без коришћења додатних објеката.

Шта је UIBezierPath?

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 и остаје стандард за креирање заобљених контејнера.

swift
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Квадратна Безјеова12
addCurveКубна Безјеова23
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:) пре сваке нове контуре.

swift
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 за ефекат „цртања“ линије од почетка до краја.

swift
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.

swift
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-а?

UIBezierPath — објектно-оријентисани омотач CGPath-а који садржи уграђене методе fill() и stroke(). CGPath је немодификовани C објекат Core Graphics-а који захтева експлицитно цртање кроз CGContext. UIBezierPath је погоднији за UIKit, CGPath је перформантнији за поновну употребу.

Како заоблити само горње углове правоугаоника?

Користите init(roundedRect:byRoundingCorners:cornerRadii:) са параметром .topLeft и .topRight за roundedRect. Ово је једини метод UIBezierPath-а који омогућава селективно заобљавање углова без креирања сложене состављене путање.

Како поново користити UIBezierPath са различитим стиловима?

Својство cgPath враћа непроменљиви CGPathRef који се може проследити CAShapeLayer-у или користити са различитим бојама и дебљинама. Модификације UIBezierPath-а (померање тачака) не утичу на раније добијени cgPath до експлицитног ажурирања.

Зашто fill() не попуњава целу путању?

Проверите usesEvenOddFillRule — ако контура има самопресецања, even-odd правило може оставити области непопуњеним. Поставите usesEvenOddFillRule = false за стандардно non-zero winding правило попуњавања.

Како анимирати облик UIBezierPath-а?

Користите CABasicAnimation са кључном путањом “path” на CAShapeLayer-у. Оба стања путање морају садржати исти број сегмената и контролних тачака — у супротном анимација ће бити трзава или неће радити.

Закључак

  • UIBezierPath — објектно-оријентисана класа UIKit-а за рад са векторским контурама и 2D графиком.
  • move(to:) и addLine(to:) — основне методе изградње правих линија и многоуглова.
  • addQuadCurve и addCurve креирају квадратне и кубне Безјеове криве са једном и две контролне тачке.
  • addArc црта лукове круга са флексибилним управљањем угловима и смером.
  • fill() и stroke() врше цртање директно у тренутном графичком контексту.
  • Иницијализатори init(roundedRect:) и init(ovalIn:) убрзавају креирање стандардних облика.
  • Својство cgPath омогућава интеграцију UIBezierPath-а са Core Animation-ом и CAShapeLayer-ом за анимацију.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође