UIBezierPath — en klass från UIKit som kapslar in en vektorbana för 2D-grafik i iOS. Den kombinerar den geometriska beskrivningen av en kontur med ritmöjligheter, vilket gör det möjligt att skapa linjer, Bézier-kurvor, bågar och rektanglar. Till skillnad från CGPath innehåller UIBezierPath egna ritmetoder direkt i den aktuella grafiska kontexten. Enligt Apple Developer Documentation, 2026 stöder UIBezierPath alla standard Quartz 2D-operationer i ett objektorienterat omslag.
Huvudpunkter
UIBezierPath — en klass i UIKit-ramverket, som ärver NSObject och implementerar NSCopying, NSSecureCoding. Den tillhandahåller ett högnivå Objective-C/Swift API för att bygga och rita vektorkonturer. Internt lagrar UIBezierPath en referens till CGPathRef — ett Core Graphics-objekt, men lägger till bekväma metoder för ritning, geometriändring och stilhantering.
Den främsta fördelen med UIBezierPath jämfört med direkt användning av CGPath är inbyggda ritmetoder. Anrop av fill() eller stroke() på en UIBezierPath-instans konfigurerar automatiskt kontexten och ritar banan. Klassen stöder också egenskaperna lineWidth, lineCapStyle, lineJoinStyle, miterLimit och flatness, vilket gör det möjligt att hantera utseendet utan ett separat objekt för stilagring.
UIBezierPath används i de flesta iOS-applikationer för anpassad ritning inuti UIView: från enkla ikoner till komplexa animerade grafer. Metoden draw(_:) i UIView-klassen är den huvudsakliga platsen där utvecklare skapar och ritar UIBezierPath. Klassen är fullt kompatibel med Core Animation och kan användas för bananimering via CAShapeLayer och CABasicAnimation.
Metoden move(to:) flyttar banans startpunkt till de angivna koordinaterna utan att rita. Detta är ett obligatoriskt anrop före byggandet av ett segment. addLine(to:) lägger till ett rakt segment från den aktuella positionen till den angivna punkten. För att stänga konturen används metoden close(), som drar en linje från den sista punkten till den första punkten av den senaste move(to:).
UIBezierPath tillhandahåller flera bekväma initierare för färdiga former. init(rect:) skapar en rektangel, init(roundedRect:cornerRadius:) — en rektangel med rundade hörn. Parametern UIRectCorner gör det möjligt att runda endast valda hörn, till exempel topLeft och bottomRight, medan de andra förblir raka. Detta används ofta för att skapa anpassade knappar och kort.
init(ovalIn:) skapar en ellips inskriven i den angivna rektangeln. Om rektangeln är en kvadrat förvandlas ellipsen till en cirkel. init(roundedRect:byRoundingCorners:cornerRadii:) — den mest flexibla varianten, som gör det möjligt att ställa in olika radier för varje hörn. Denna initierare dök upp i iOS 6 och förblir standarden för att skapa rundade containrar.
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:) lägger till en kvadratisk Bézier-kurva med en kontrollpunkt. Denna kurvtyp används för enkla mjuka böjningar när man vill minimera antalet beräkningar. Den kvadratiska kurvan är alltid en parabel och ligger garanterat inom triangeln som bildas av start-, kontroll- och slutpunkterna.
addCurve(to:controlPoint1:controlPoint2:) lägger till en kubisk Bézier-kurva med två kontrollpunkter. Kubiska kurvor används i alla moderna vektorredigerare och TrueType-teckensnitt. Två kontrollpunkter ger fler frihetsgrader för exakt kontroll av kurvformen. Denna metod rekommenderas för att bygga organiska och komplexa konturer.
Vid byggande av kurvor är det viktigt att följa kontinuitetsprincipen — kurvans jämnhet vid segmentens föreningspunkt. För C1-kontinuitet (tangent) måste kontrollpunkten för nästa kurva ligga på samma raka linje som kontrollpunkten för den föregående. För C2-kontinuitet (krökning) krävs en mer komplex anpassning, som automatiskt säkerställs i CAShapeLayer vid animering mellan två UIBezierPath med samma antal kontrollpunkter.
| Metod | Typ | Kontrollpunkter | Grad |
|---|---|---|---|
| addQuadCurve | Kvadratisk Bézier | 1 | 2 |
| addCurve | Kubisk Bézier | 2 | 3 |
| addArc | Båge | — | — |
addArc(withCenter:radius:startAngle:endAngle:clockwise:) lägger till en cirkelbåge med de angivna parametrarna. Vinklar anges i radianer i förhållande till cirkelns centrum. Noll vinkel motsvarar riktningen åt höger (klockan 3 på urtavlan). Parametern clockwise bestämmer riktningen: true — medurs, false — moturs. Bågar är oumbärliga för cirkeldiagram, hastighetsmätare och interaktiva framstegsringar.
För en hel cirkel räcker startAngle = 0 och endAngle = .pi * 2. För att skapa en sektor (som en del av ett cirkeldiagram) använd addArc följt av addLine(to:) till centrum och close(). UIBezierPath har ingen inbyggd addCircle-metod — en cirkel skapas via init(ovalIn:) med en kvadratisk rektangel eller via addArc med full vinkel.
Metoden addArc(withCenter:radius:startAngle:endAngle:clockwise:) utför automatiskt move(to:) till bågens startpunkt om den aktuella positionen inte sammanfaller med den. Om den aktuella positionen är annorlunda, dras en rak linje mellan den och bågens början. Detta beteende skiljer sig från arbete med Core Graphics, där en explicit move(to:) krävs före varje ny kontur.
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() fyller banans inre område med den aktuella fillColor-färgen eller färgen som ställts in i den grafiska kontexten via setFill(). För banor med självkorsningar bestäms fyllningsregeln av egenskapen usesEvenOddFillRule. Om den är true tillämpas even-odd-regeln: en punkt anses vara innanför formen om en stråle från den skär konturen ett udda antal gånger.
stroke() ritar banans kontur med de aktuella inställningarna för lineWidth, lineCapStyle och lineJoinStyle. lineCapStyle bestämmer formen på ändarna av öppna segment: .butt (rakt snitt), .round (halvcirkelformad), .square (fyrkantig med utskott). lineJoinStyle bestämmer formen på förbindningshörn: .miter (vass), .round (rundad), .bevel (avskuren).
För streckade linjer används egenskapen setLineDash(_:count:phase:). Den tar emot en array av längder av växlande streck och mellanrum, antalet element och en startfas. Visualiseringen av den streckade linjen sker i rastreringsfasen av banan — komplexa mönster ökar inte konturens geometriska komplexitet. CAShapeLayer stöder animering av egenskapen strokeEnd för effekten av att “rita” en linje från början till slut.
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()
}
Låt oss skapa en anpassad framstegsindikator i form av en ring med UIBezierPath. Ringen byggs av två bågar med samma radie men olika streckningsfärg. Den första bågen är en hel grå cirkel (bakgrund), den andra är ett segment som visar framsteg. För animering används CAShapeLayer och 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
}
}
I detta exempel används UIBezierPath för att skapa en cirkulär kontur, som sedan skickas till CAShapeLayer via egenskapen cgPath. Animeringen av strokeEnd från 0 till 1 visualiserar fyllningen av ringen. Detta tillvägagångssätt används i laddningsindikatorer, fitness-trackers och framstegswidgetar. Metoden layoutSubviews garanterar ombyggnad av banan vid ändring av View-dimensioner.
lineCap = .round lägger till rundade ändar på bågen, vilket ger indikatorn ett mer ordnat utseende. Egenskapen strokeEnd är en animerbar egenskap hos CAShapeLayer som inte kräver omritning av hela konturen i varje bildruta. Animeringen utförs helt på GPU via Core Animation, vilket säkerställer 60 FPS utan CPU-belastning.
Vanliga frågor
UIBezierPath — objektorienterat omslag av CGPath som innehåller inbyggda fill()- och stroke()-metoder. CGPath är ett oföränderligt C Core Graphics-objekt som kräver explicit ritning via CGContext. UIBezierPath är bekvämare för UIKit, CGPath är effektivare för återanvändning.
Använd init(roundedRect:byRoundingCorners:cornerRadii:) med parametern .topLeft och .topRight för roundedRect. Detta är den enda UIBezierPath-metoden som möjliggör selektiv avrundning av hörn utan att skapa en komplex sammansatt bana.
Egenskapen cgPath returnerar en oföränderlig CGPathRef som kan skickas till CAShapeLayer eller användas med olika färger och tjocklekar. Ändringar av UIBezierPath (flyttning av punkter) påverkar inte tidigare erhållen cgPath förrän explicit uppdatering.
Kontrollera usesEvenOddFillRule — om konturen har självkorsningar kan even-odd-regeln lämna områden ofyllda. Ställ in usesEvenOddFillRule = false för standardregeln för non-zero winding-fyllning.
Använd CABasicAnimation med nyckelsökvägen “path” på CAShapeLayer. Båda banornas tillstånd måste innehålla samma antal segment och kontrollpunkter — annars kommer animeringen att vara hackig eller inte fungera.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också