draw(_:) / drawRect — ez a UIView osztály metódusa (Swift-ben) és annak analógja Objective-C-ben (drawRect:), amely a nézet tartalmának Core Graphics segítségével történő megjelenítéséért felelős. A rendszer automatikusan meghívja ezt a metódust a nézet első képernyőn történő megjelenésekor és a setNeedsDisplay() meghívása után. Az Apple Documentation (2025) szerint a draw(_:) az egyetlen metódus, ahol a fejlesztő hozzáfér az aktuális képernyő grafikus kontextusához egyedi rajzoláshoz. A draw(_:) felülbírálása teljes irányítást ad a komponens megjelenése felett — az egyszerű geometriai alakzatoktól a bonyolult animált grafikáig.
Főbb pontok
draw(_:) — egy UIView példánymetódus, amelyet a UIKit hív meg a nézet tartalmának megjelenítéséhez. A metódus belsejében a fejlesztő hozzáfér a CGContext grafikus kontextushoz, és a Core Graphics API-t használja vonalak, kitöltések, szövegek és képek rajzolásához. A drawRect: Objective-C-ben ugyanazt a funkciót látja el, de eltérő szintaxissal: az egyetlen paraméter egy CGRect, amely az újrarajzolandó területet adja meg.
Az Apple Engineering (2024) szerint a draw(_:) CPU-megjelenítésen, Bitmap Graphics Context-en keresztül működik, ami maximális rugalmasságot biztosít, de több erőforrást igényel a CALayer-hez képest. A draw(_:) használatáról szóló döntést a grafika összetettsége és a teljesítménykövetelmények alapján hozzák meg.
Swift-ben a metódus override func draw(_ rect: CGRect) formában van deklarálva, ahol rect az újrarajzolandó téglalap. Objective-C-ben az aláírás - (void)drawRect:(CGRect)rect. A rect paraméter kisebb lehet a nézet bounds-ánál részleges újrarajzolás esetén a setNeedsDisplay(_:) híváson keresztül.
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rect);
}
A rendszer automatikusan meghívja a draw(_:)-t szigorúan meghatározott forgatókönyvekben. Ezen triggerek megértése segít elkerülni a felesleges újrarajzolásokat és optimalizálni a nézet teljesítményét. Az alábbiakban felsoroljuk a metódus automatikus meghívásának összes esetét.
Az Apple dokumentációja figyelmeztet: soha ne hívd meg közvetlenül a draw(_:)-t. A rendszer maga dönti el, mikor végezze el a rajzolást, és a közvetlen hívás megzavarja a belső gyorsítótárazási mechanizmust. Az újrarajzolás kéréséhez mindig a setNeedsDisplay() vagy a setNeedsDisplay(_:) használata javasolt.
A draw(_:) felülbírálása Swift-ben a grafikus kontextus lekérésével és az azt követő Core Graphics hívásokkal kezdődik. Javasolt külön metódusokat létrehozni a rajzolás logikai blokkjaihoz — ez javítja a kód olvashatóságát és tesztelhetőségét.
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else { return }
// Vonal paraméterei
context.setStrokeColor(UIColor.darkGray.cgColor)
context.setLineWidth(2.0)
// Háromszög rajzolása
context.move(to: CGPoint(x: rect.midX, y: rect.minY + 10))
context.addLine(to: CGPoint(x: rect.maxX - 10, y: rect.maxY - 10))
context.addLine(to: CGPoint(x: rect.minX + 10, y: rect.maxY - 10))
context.closePath()
context.strokePath()
}
Ebben a példában a draw(_:) egy háromszöget rajzol 2 pixel vastag sötétszürke körvonallal. A super.draw(rect) hívása a metódus elején az Apple által javasolt a szülő rajzolási logikájának megőrzése érdekében, bár a UIView alapértelmezett draw(_:) implementációja üres.
A draw(_:) minden hívásának azonos bemeneti adatok mellett azonos eredményt kell adnia. Ez lehetővé teszi a rendszer számára, hogy gyorsítótárazza az eredményt, és ne hívja meg újra a draw(_:)-t, ha a nézet tartalma nem változott. Ne használj a draw(_:) belsejében véletlenszerű értékeket, rendszeridőt vagy hálózati kéréseket.
drawRect: — történetileg a metódus első változata, amely az iOS 2.0-ban jelent meg az Objective-C-vel együtt. Swift-ben a metódust draw(_:)-re nevezték át a _ külső paraméter használatával. Funkcionálisan a metódusok azonosak: mindkettő megkapja az újrarajzolandó terület CGRect-jét, és a UIGraphicsGetCurrentContext() segítségével éri el a grafikus kontextust.
| Jellemző | draw(_:) (Swift) | drawRect: (Objective-C) |
|---|---|---|
| Aláírás | override func draw(_ rect: CGRect) | - (void)drawRect:(CGRect)rect |
| Super hívás | super.draw(rect) | [super drawRect:rect] |
| Kontextus | UIGraphicsGetCurrentContext() | UIGraphicsGetCurrentContext() |
| Paraméter rect | rect: CGRect | CGRect rect |
| Teljesítmény | Azonos | Azonos |
A projekt Objective-C-ről Swift-re történő migrálásakor a metódus átnevezése az egyik első feladat. Az Xcode automatikus konvertert biztosít, de a drawRect: kézi frissítést igényel draw(_:)-re. Az Apple (2024) szerint a Swift draw(_:) változata előnyösebb az új projektekhez.
A draw(_:) CPU-n fut, és a nem optimális implementáció képkocka-kiesést és alacsony teljesítményt okozhat. Az Apple több bevált megközelítést javasol a rajzolás felgyorsításához.
Minden Core Graphics műveletnek (move(to:), addLine(to:), strokePath) van többletköltsége. Csoportosítsd a műveleteket, és használj CGPath-t összetett alakzatokhoz — az útvonal egyszer jön létre, és minden draw(_:) híváskor újra felhasználható.
UIBezierPath — egy Objective-C burkoló a CGPath körül, amely egyszerű API-t biztosít alakzatok létrehozásához. Hozd létre a UIBezierPath-t előre (pl. az inicializátorban), és egyszerűen hívd meg a fill() vagy stroke() metódust a draw(_:) belsejében.
private let starPath: UIBezierPath = {
let path = UIBezierPath()
// Csillag alakzat létrehozása
path.move(to: CGPoint(x: 50, y: 0))
for i in 1...5 {
let angle = CGFloat(i) * 4 * CGFloat.pi / 5
path.addLine(to: CGPoint(x: 50 + 40 * cos(angle),
y: 50 + 40 * sin(angle)))
}
path.close()
return path
}()
override func draw(_ rect: CGRect) {
UIColor.systemYellow.setFill()
starPath.fill()
}
A fejlesztők gyakran ugyanazokat a hibákat követik el a draw(_:) felülbírálásakor. Ezen minták ismerete segít elkerülni a hibákat és a teljesítmény romlását. Tekintsük át a leggyakoribb problémákat és megoldásaikat.
E szabályok betartásával stabil és gyors egyedi nézetek rajzolását biztosíthatod bármely iOS projektben. Profilozd a draw(_:)-t az Instruments (Core Animation) segítségével, hogy lásd a tényleges végrehajtási időt és a szűk keresztmetszeteket.
Gyakran Ismételt Kérdések
Nem, a draw(_:) közvetlen meghívása tilos az Apple dokumentációja szerint. A rendszer maga kezeli a rajzolási ciklust. Az újrarajzolás kéréséhez használd a setNeedsDisplay()-t, amely helyesen jelöli meg a nézetet frissítendőként a legközelebbi renderelési ciklusban.
Funkcionálisan ezek a metódusok azonosak. A drawRect: Objective-C-ben használatos, a draw(_:) — Swift-ben. Mindkettő megkapja az újrarajzolandó terület CGRect-jét, és ugyanazt a Core Graphics kontextust használja a UIGraphicsGetCurrentContext() segítségével.
Az Apple optimalizálja a renderelést: ha a UIView-nek nincs felülbírált draw(_:)-je, a rendszer nem hoz létre bitmap kontextust számára. Ez memóriát takarít meg. Ha a felülbírálás létezik, de a metódus nem hívódik meg — ellenőrizd, hogy a nézet kerete nem nulla-e és a nézet látható-e.
Csak szükség esetén: első renderelés, setNeedsDisplay() után, bounds változásakor contentMode = .redraw esetén. Statikus állapotban a draw(_:) nem hívódik meg újra, ami CPU-t és akkumulátort takarít meg.
Az Apple javasolja a super.draw(rect) meghívását a felülbírált metódus elején. Bár a UIView jelenlegi implementációja üres, a super hívás biztosítja a kompatibilitást a jövőbeli UIKit verziókkal, és jó gyakorlat.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is