draw(_:) a drawRect — co to je, volání a přepsání

Autor: IT Sectr Publikováno: 2026-07-20 Doba čtení: 7 min

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(_:) — metoda UIView pro vlastní kreslení přes Core Graphics, není volána přímo vývojářem
  • drawRect: — ekvivalent draw(_:) v Objective-C, syntakticky odlišný, funkčně identický
  • CGContext — grafický kontext dostupný uvnitř draw(_:) pro všechny operace kreslení
  • setNeedsDisplay() — jediný správný způsob, jak požádat o opětovné volání draw(_:) ze strany vývojáře
  • UIGraphicsGetCurrentContext() — funkce pro získání aktuálního kontextu uvnitř draw(_:), povinný krok před kreslením

Co je draw(_:) / drawRect

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.

Signatura metody ve Swiftu a Objective-C

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(_:).

objective-c
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
    CGContextFillRect(context, rect);
}

Kdy systém volá draw(_:)

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.

  • První vykreslení — když je view poprvé přidáno do hierarchie a stane se viditelným na obrazovce
  • setNeedsDisplay() — po volání této metody systémem v nejbližším cyklu kreslení
  • setNeedsDisplay(_:) — totéž, ale s určením konkrétního obdélníku pro překreslení
  • contentMode — při změně bounds, pokud contentMode vyžaduje překreslení (např. .redraw)
  • setNeedsLayout() — v některých případech může být po přeuspořádání subview vyžadováno překreslení

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(_:).

Jak přepsat draw(_:) ve Swiftu

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.

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

Pravidlo idempotence draw(_:)

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: v Objective-C a rozdíl oproti draw(_:)

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.

Vlastnostdraw(_:) (Swift)drawRect: (Objective-C)
Signaturaoverride func draw(_ rect: CGRect)- (void)drawRect:(CGRect)rect
Volání supersuper.draw(rect)[super drawRect:rect]
KontextUIGraphicsGetCurrentContext()UIGraphicsGetCurrentContext()
Parametr rectrect: CGRectCGRect rect
VýkonIdentický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.

Optimalizace kreslení v draw(_:)

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

Minimalizujte počet operací 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(_:).

Používejte UIBezierPath pro vektorové objekty

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(_:).

swift
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()
}

Typické chyby při práci s draw(_:)

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

  • Přímé volání draw(_:) — nikdy nevolejte draw(_:) přímo. Pro vyžádání překreslení použijte setNeedsDisplay(). Přímé volání narušuje ukládání do mezipaměti a může vést k nesprávnému zobrazení.
  • Těžké výpočty uvnitř draw(_:) — draw(_:) by měla být co nejlehčí. Vytvářejte UIBezierPath, obrázky a další těžké objekty mimo metodu, inicializujte je jednou.
  • Vytváření objektů uvnitř draw(_:) — konstrukce UIColor, UIFont a UIGraphicsImageRenderer uvnitř draw(_:) vytvářejí dodatečné paměťové zatížení. Přesuňte vytváření objektů do vlastností třídy.
  • Ignorování parametru rect — rect označuje oblast vyžadující překreslení. Kreslení mimo rect je systémem odmítnuto, ale spotřebovává zdroje. Před kreslením zkontrolujte průnik s rect.
  • Chybějící super.draw(rect) — ačkoli je implementace UIView prázdná, Apple doporučuje volání super.draw(rect) pro kompatibilitu s budoucími změnami UIKit.

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

Lze draw(_:) volat přímo?

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

Čím se liší drawRect: od draw(_:)?

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().

Proč se draw(_:) nevolá pro prázdný UIView?

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

Jak často systém volá draw(_:)?

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.

Je třeba volat super.draw(rect) ve Swiftu?

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í

  • draw(_:) / drawRect — hlavní metoda kreslení UIView ve Swiftu a Objective-C, volaná automaticky systémem
  • CGContext — grafický kontext Core Graphics dostupný uvnitř draw(_:) přes UIGraphicsGetCurrentContext()
  • setNeedsDisplay() — správný způsob vyžádání překreslení; přímé volání draw(_:) je zakázáno
  • Idempotence — draw(_:) by měla poskytovat stejný výsledek při stejných vstupních datech pro správné ukládání do mezipaměti
  • UIBezierPath — vytvářejte cesty mimo draw(_:) pro minimalizaci zatížení CPU při každém volání
  • Parametr rect — obsahuje oblast překreslení; používejte intersection pro optimalizaci — nekreslete mimo jeho hranice
  • Profilování — kontrolujte výkon draw(_:) pomocí Instruments Core Animation pro odhalení pomalých operací

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

Prodiskutovat projekt

Přečtěte si také