draw(_:) / drawRect — je metoda třídy UIView (ve Swiftu) a její analogie v Objective-C (drawRect:), která je zodpovědná za vykreslování obsahu view pomocí Core Graphics. Systém volá tuto metodu automaticky při prvním zobrazení view na obrazovce a po volání setNeedsDisplay(). Podle Apple Documentation (2025) je draw(_:) jedinou metodou, kde má vývojář přístup ke grafickému kontextu aktuální obrazovky pro vlastní kreslení. Přepsání draw(_:) poskytuje plnou kontrolu nad vzhledem komponenty — od jednoduchých geometrických tvarů až po složitou animovanou grafiku.
Hlavní body
draw(_:) — je instanční metoda UIView, kterou UIKit volá pro vykreslení obsahu view. Uvnitř této metody získá vývojář přístup ke grafickému kontextu CGContext a používá API Core Graphics pro kreslení čar, výplní, textu a obrázků. drawRect: v Objective-C plní stejnou funkci, ale s odlišnou syntaxí: jediným parametrem je CGRect určující oblast pro překreslení.
Podle Apple Engineering (2024) draw(_:) pracuje přes CPU-rendering Bitmap Graphics Context, což poskytuje maximální flexibilitu, ale vyžaduje více prostředků ve srovnání s CALayer. Rozhodnutí o použití draw(_:) se přijímá na základě složitosti grafiky a požadavků na výkon.
Ve Swiftu je metoda deklarována jako override func draw(_ rect: CGRect), kde rect je obdélník, který je třeba překreslit. V Objective-C je signatura - (void)drawRect:(CGRect)rect. Parametr rect může být menší než bounds view při částečném překreslení pomocí setNeedsDisplay(_:).
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rect);
}
Systém automaticky volá draw(_:) v přesně definovaných scénářích. Pochopení těchto spouštěčů pomáhá vyhnout se zbytečnému překreslování a optimalizovat výkon view. Níže jsou uvedeny všechny případy automatického volání metody.
Apple dokumentace varuje: nikdy nevolejte draw(_:) přímo. Systém sám rozhoduje, kdy provést kreslení, a přímé volání narušuje interní mechanismus ukládání do mezipaměti. Pro vyžádání překreslení vždy používejte setNeedsDisplay() nebo setNeedsDisplay(_:).
Přepsání draw(_:) ve Swiftu začíná získáním grafického kontextu a následnými voláními Core Graphics. Doporučuje se vytvářet samostatné metody pro logické bloky kreslení — to zlepšuje čitelnost a testovatelnost kódu.
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else { return }
// Parametry čáry
context.setStrokeColor(UIColor.darkGray.cgColor)
context.setLineWidth(2.0)
// Kreslení trojúhelníku
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()
}
V tomto příkladu draw(_:) kreslí trojúhelník s tmavě šedým obrysem o tloušťce 2 pixely. Volání super.draw(rect) na začátku metody je doporučeno Applem pro zachování rodičovské logiky kreslení, ačkoli výchozí implementace draw(_:) v UIView je prázdná.
Každé volání draw(_:) by mělo poskytnout identický výsledek při stejných vstupních datech. To umožňuje systému ukládat výsledek do mezipaměti a nevolat draw(_:) znovu, pokud se obsah view nezměnil. Nepoužívejte uvnitř draw(_:) náhodné hodnoty, systémový čas nebo síťové požadavky.
drawRect: — historicky první verze metody, která se objevila v iOS 2.0 spolu s Objective-C. Ve Swiftu byla metoda přejmenována na draw(_:) s použitím externího parametru _. Funkčně jsou metody identické: obě přijímají CGRect oblasti překreslení a používají UIGraphicsGetCurrentContext() pro přístup ke grafickému kontextu.
| Vlastnost | draw(_:) (Swift) | drawRect: (Objective-C) |
|---|---|---|
| Signatura | override func draw(_ rect: CGRect) | - (void)drawRect:(CGRect)rect |
| Volání super | super.draw(rect) | [super drawRect:rect] |
| Kontext | UIGraphicsGetCurrentContext() | UIGraphicsGetCurrentContext() |
| Parametr rect | rect: CGRect | CGRect rect |
| Výkon | Identický | Identický |
Při migraci projektu z Objective-C na Swift je přejmenování metody jedním z prvních úkolů. Xcode poskytuje automatický konvertor, ale drawRect: vyžaduje ruční aktualizaci na draw(_:). Podle Apple (2024) je Swift verze draw(_:) preferována pro nové projekty.
draw(_:) se provádí na CPU a neoptimální implementace může způsobit pokles snímků a nízký výkon. Apple doporučuje několik osvědčených postupů pro urychlení kreslení.
Každá operace Core Graphics (move(to:), addLine(to:), strokePath) má režii. Seskupujte operace a používejte CGPath pro složité tvary — cesta se vytvoří jednou a znovu používá při každém volání draw(_:).
UIBezierPath — je Objective-C obal kolem CGPath, který poskytuje jednoduché API pro vytváření tvarů. Vytvořte UIBezierPath předem (např. v inicializátoru) a jednoduše volejte fill() nebo stroke() uvnitř draw(_:).
private let starPath: UIBezierPath = {
let path = UIBezierPath()
// Vytvoření tvaru hvězdy
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()
}
Vývojáři často dělají stejné chyby při přepisování draw(_:). Znalost těchto vzorců pomáhá vyhnout se chybám a snížení výkonu. Podívejme se na nejčastější problémy a jejich řešení.
Dodržováním těchto pravidel zajistíte stabilní a rychlé kreslení vlastních view v jakémkoli iOS projektu. Profilujte draw(_:) pomocí Instruments (Core Animation), abyste viděli skutečný čas provádění a úzká místa.
Často kladené otázky
Ne, přímé volání draw(_:) je zakázáno dokumentací Apple. Systém sám řídí cyklus kreslení. Pro vyžádání překreslení použijte setNeedsDisplay(), který správně označí view jako vyžadující aktualizaci v nejbližším cyklu vykreslování.
Funkčně jsou tyto metody identické. drawRect: se používá v Objective-C, draw(_:) — ve Swiftu. Obě přijímají CGRect oblasti překreslení a používají stejný Core Graphics kontext prostřednictvím UIGraphicsGetCurrentContext().
Apple optimalizuje vykreslování: pokud UIView nemá přepsanou draw(_:), systém pro něj nevytváří bitmapový kontext. To šetří paměť. Pokud přepsání existuje, ale metoda se nevolá — zkontrolujte, že rám view není nulový a view je viditelné.
Pouze v případě potřeby: první vykreslení, po setNeedsDisplay(), při změně bounds s contentMode = .redraw. Ve statickém stavu se draw(_:) nevolá znovu, což šetří prostředky CPU a baterii.
Apple doporučuje volat super.draw(rect) na začátku přepsané metody. Ačkoli je aktuální implementace UIView prázdná, volání super zajišťuje kompatibilitu s budoucími verzemi UIKit a je dobrou praxí.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také