UIBezierPath — o clasă din UIKit care încapsulează o cale vectorială pentru grafica 2D în iOS. Combină descrierea geometrică a conturului cu capacitățile de desenare, permițând crearea de linii, curbe Bézier, arcuri și dreptunghiuri. Spre deosebire de CGPath, UIBezierPath conține metode proprii de desenare direct în contextul grafic curent. Conform Apple Developer Documentation, 2026, UIBezierPath suportă toate operațiile standard Quartz 2D într-o îmbrăcăminte orientată pe obiecte.
Principalele puncte
UIBezierPath — o clasă a framework-ului UIKit, moștenind NSObject și implementând NSCopying, NSSecureCoding. Oferă un API de nivel înalt Objective-C/Swift pentru construirea și desenarea contururilor vectoriale. Intern, UIBezierPath stochează o referință la CGPathRef — un obiect Core Graphics, dar adaugă metode convenabile pentru desenare, modificarea geometriei și gestionarea stilurilor.
Principalul avantaj al UIBezierPath față de utilizarea directă a CGPath sunt metodele de desenare încorporate. Apelarea fill() sau stroke() pe o instanță UIBezierPath configurează automat contextul și desenează calea. Clasa suportă și proprietățile lineWidth, lineCapStyle, lineJoinStyle, miterLimit și flatness, permițând gestionarea aspectului fără un obiect separat pentru stocarea stilurilor.
UIBezierPath este folosit în majoritatea aplicațiilor iOS pentru desenarea personalizată în interiorul UIView: de la pictograme simple la grafice animate complexe. Metoda draw(_:) a clasei UIView este locul principal unde dezvoltatorii creează și desenează UIBezierPath. Clasa este complet compatibilă cu Core Animation și poate fi folosită pentru animarea căii prin CAShapeLayer și CABasicAnimation.
Metoda move(to:) mută punctul de pornire al căii la coordonatele date fără a desena. Aceasta este o apelare obligatorie înainte de construirea oricărui segment. addLine(to:) adaugă un segment drept de la poziția curentă la punctul specificat. Pentru închiderea conturului se folosește metoda close(), care trasează o linie de la ultimul punct la primul punct al ultimului move(to:).
UIBezierPath oferă mai mulți inițializatori convenabili pentru figuri gata făcute. init(rect:) creează un dreptunghi, init(roundedRect:cornerRadius:) — un dreptunghi cu colțuri rotunjite. Parametrul UIRectCorner permite rotunjirea doar a colțurilor selectate, de exemplu topLeft și bottomRight, lăsându-le pe celelalte drepte. Acest lucru este utilizat pe scară largă pentru crearea de butoane și carduri personalizate.
init(ovalIn:) creează o elipsă înscrisă în dreptunghiul dat. Dacă dreptunghiul este un pătrat, elipsa se transformă într-un cerc. init(roundedRect:byRoundingCorners:cornerRadii:) — cea mai flexibilă variantă, permițând setarea unor raze diferite pentru fiecare colț. Acest inițializator a apărut în iOS 6 și rămâne standardul pentru crearea containerelor rotunjite.
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:) adaugă o curbă Bézier pătratică cu un punct de control. Acest tip de curbă este folosit pentru îndoiri line simple, când se dorește minimizarea numărului de calcule. Curba pătratică este întotdeauna o parabolă și se află garantat în interiorul triunghiului format de punctele de pornire, control și final.
addCurve(to:controlPoint1:controlPoint2:) adaugă o curbă Bézier cubică cu două puncte de control. Curbele cubice sunt utilizate în toate editoarele vectoriale moderne și fonturile TrueType. Două puncte de control oferă mai multe grade de libertate pentru controlul precis al formei curbei. Această metodă este recomandată pentru construirea contururilor organice și complexe.
La construirea curbelor este important să se respecte principiul continuității — netezimea curbei în punctul de îmbinare a segmentelor. Pentru continuitatea C1 (tangentă), punctul de control al curbei următoare trebuie să se afle pe aceeași linie dreaptă cu punctul de control al precedentei. Pentru continuitatea C2 (curbură) este necesară o ajustare mai complexă, care este asigurată automat în CAShapeLayer la animația între două UIBezierPath cu același număr de puncte de control.
| Metodă | Tip | Puncte de control | Grad |
|---|---|---|---|
| addQuadCurve | Bézier pătratică | 1 | 2 |
| addCurve | Bézier cubică | 2 | 3 |
| addArc | Arc | — | — |
addArc(withCenter:radius:startAngle:endAngle:clockwise:) adaugă un arc de cerc cu parametrii dați. Unghiurile sunt specificate în radiani față de centrul cercului. Unghiul zero corespunde direcției spre dreapta (ora 3 pe cadran). Parametrul clockwise determină direcția: true — în sensul acelor de ceas, false — invers. Arcurile sunt indispensabile pentru diagrame circulare, vitezometre și inele interactive de progres.
Pentru un cerc complet sunt suficiente startAngle = 0 și endAngle = .pi * 2. Pentru crearea unui sector (ca parte a unei diagrame circulare) utilizați addArc urmat de addLine(to:) la centru și close(). UIBezierPath nu are o metodă încorporată addCircle — cercul se creează prin init(ovalIn:) cu un dreptunghi pătrat sau prin addArc cu unghi complet.
Metoda addArc(withCenter:radius:startAngle:endAngle:clockwise:) execută automat move(to:) la punctul de pornire al arcului dacă poziția curentă nu coincide cu acesta. Dacă poziția curentă este diferită, între ea și începutul arcului se trasează o linie dreaptă. Acest comportament diferă de lucrul cu Core Graphics, unde este necesar un move(to:) explicit înainte de fiecare nou contur.
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() umple zona interioară a căii cu culoarea curentă fillColor sau culoarea setată în contextul grafic prin setFill(). Pentru căi cu auto-intersectări, regula de umplere este determinată de proprietatea usesEvenOddFillRule. Dacă este true, se aplică regula even-odd: un punct este considerat în interiorul figurii dacă raza din el intersectează conturul de un număr impar de ori.
stroke() desenează conturul căii cu setările curente lineWidth, lineCapStyle și lineJoinStyle. lineCapStyle determină forma capetelor segmentelor deschise: .butt (tăietură dreaptă), .round (semi-circular), .square (pătrat cu proeminență). lineJoinStyle specifică forma colțurilor îmbinărilor: .miter (ascuțit), .round (rotunjit), .bevel (tăiat).
Pentru linii întrerupte se utilizează proprietatea setLineDash(_:count:phase:). Aceasta primește un tablou de lungimi alternante de linii și spații, numărul de elemente și faza inițială. Vizualizarea liniei întrerupte are loc în etapa de rasterizare a căii — modelele complexe nu cresc complexitatea geometrică a conturului. CAShapeLayer suportă animația proprietății strokeEnd pentru efectul de „desenare“ a liniei de la început la sfârșit.
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()
}
Să creăm un indicator de progres personalizat sub formă de inel folosind UIBezierPath. Inelul se construiește din două arcuri de aceeași rază, dar cu culoare diferită a conturului. Primul arc — un cerc complet de culoare gri (fundal), al doilea — segmentul care arată progresul. Pentru animație se folosesc CAShapeLayer și 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
}
}
În acest exemplu UIBezierPath este folosit pentru a crea un contur circular, care apoi este transmis către CAShapeLayer prin proprietatea cgPath. Animația strokeEnd de la 0 la 1 vizualizează umplerea inelului. Această abordare este folosită în indicatorii de încărcare, trackerele de fitness și widgeturile de progres. Metoda layoutSubviews garantează reconstruirea căii la modificarea dimensiunilor View.
lineCap = .round adaugă capete rotunjite arcului, conferind indicatorului un aspect mai îngrijit. Proprietatea strokeEnd este o proprietate animabilă a CAShapeLayer care nu necesită redesenarea întregului contur în fiecare cadru. Animația este executată complet pe GPU prin Core Animation, asigurând 60 FPS fără încărcarea CPU.
Întrebări frecvente
UIBezierPath — îmbrăcămintea orientată pe obiecte a CGPath care conține metode încorporate fill() și stroke(). CGPath este un obiect C nemodificabil al Core Graphics care necesită desenare explicită prin CGContext. UIBezierPath este mai convenabil pentru UIKit, CGPath este mai performant pentru reutilizare.
Utilizați init(roundedRect:byRoundingCorners:cornerRadii:) cu parametrul .topLeft și .topRight pentru roundedRect. Aceasta este singura metodă UIBezierPath care permite rotunjirea selectivă a colțurilor fără a crea o cale compusă complexă.
Proprietatea cgPath returnează un CGPathRef imutabil care poate fi transmis către CAShapeLayer sau folosit cu culori și grosimi diferite. Modificările UIBezierPath (mutarea punctelor) nu afectează cgPath-ul obținut anterior până la actualizarea explicită.
Verificați usesEvenOddFillRule — dacă conturul are auto-intersectări, regula even-odd poate lăsa zone neumplute. Setați usesEvenOddFillRule = false pentru regula standard de umplere non-zero winding.
Utilizați CABasicAnimation cu calea cheie “path” pe CAShapeLayer. Ambele stări ale căii trebuie să conțină același număr de segmente și puncte de control — în caz contrar animația va fi sacadată sau nu va funcționa.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și