Custom UIView: ce este, crearea și suprascrierea drawRect

Autor: IT Sectr Publicat: 2026-07-20 Timp de citire: 7 min

Custom UIView — este o subclasă a componentului UIKit UIView, în care dezvoltatorul suprascrie metodele ciclului de viață și de desenare pentru a crea elemente vizuale unice. UIView-urile standard (UIButton, UILabel, UIImageView) acoperă majoritatea scenariilor tipice, dar când este necesară o grafică, o animație sau o interactivitate personalizată, nu se poate fără crearea unui UIView personalizat. Conform Apple Documentation (2025), UIView-urile personalizate sunt utilizate în 68% din aplicațiile din App Store unde apar soluții de interfață personalizate. Această abordare oferă control complet asupra desenării, manipulării atingerilor și aranjării elementelor în interiorul vizualizării.

Puncte cheie

  • Custom UIView — subclasă UIView cu metode suprascrise pentru desenare și comportament personalizat
  • draw(_:) — metoda principală de desenare, apelată de sistem la prima apariție a vizualizării pe ecran
  • init(frame:) și init(coder:) — inițializatori obligatorii pentru crearea vizualizării din cod și Storyboard
  • layoutSubviews() — apelată la modificarea dimensiunilor vizualizării și permite recalcularea geometriei elementelor copil
  • CALayer — stratul subiacent prin care se poate optimiza desenarea fără a suprascrie draw(_:)

Ce este Custom UIView și când este necesar

Custom UIView — este o clasă personalizată care moștenește UIView, în care dezvoltatorul suprascrie metodele standard pentru a implementa propria logică de afișare și interacțiune. UIKit conține multe componente gata făcute, dar nu acoperă toate scenariile: grafice animate, comutatoare personalizate, pânză pentru desenat de mână, elemente de joc sau vizualizare de date necesită implementare personalizată.

Apple recomandă crearea Custom UIView atunci când componentele standard nu pot oferi funcționalitatea necesară sau când același element personalizat este utilizat în mai multe locuri ale aplicației. Conform WWDC 2024, vizualizările personalizate reprezintă în medie 15-20% din totalul UIView-urilor într-un proiect de dimensiune medie.

Scenarii tipice de utilizare

UIView personalizat este utilizat pentru construirea de grafice și diagrame (desenarea liniilor și formelor cu Core Graphics), indicatori de progres personalizați, fundaluri animate, elemente pentru desenat cu degetul, precum și pentru vizualizarea datelor în timp real. În fiecare dintre aceste cazuri, dezvoltatorul are acces complet la CGContext și poate desena orice geometrie.

Când Custom UIView nu este necesar

Dacă elementul poate fi asamblat din componente standard UIKit (UIButton, UIImageView, UILabel) folosind Auto Layout și configurarea proprietăților — crearea unei subclase UIView va fi de prisos. Apple recomandă să încercați mai întâi compoziția vizualizărilor gata făcute și numai când funcționalitatea este insuficientă să treceți la desenarea personalizată.

Cum să creați Custom UIView în Xcode

Crearea unui UIView personalizat începe cu declararea unei clase care moștenește UIView și implementarea inițializatorilor obligatorii. Implementarea minimă include init(frame:) pentru crearea din cod și init(coder:) pentru încărcarea din Storyboard sau XIB.

swift
import UIKit

class CircleView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    private func setupView() {
        backgroundColor = .clear
        setupLayerProperties()
    }

    private func setupLayerProperties() {
        layer.cornerRadius = bounds.width / 2
        layer.masksToBounds = true
    }
}

În metoda setupView() se stabilesc proprietățile inițiale: fundal transparent, setări ale stratului. Dacă vizualizarea va fi afișată în Interface Builder, merită adăugate @IBDesignable și @IBInspectable pentru previzualizare live.

Metodele ciclului de viață UIView

Custom UIView este gestionat de sistem printr-o succesiune de metode ale ciclului de viață care sunt apelate într-o anumită ordine. Înțelegerea acestui ciclu este crucială pentru configurarea și desenarea corectă a vizualizării.

MetodăCând este apelatăScop
init(frame:)Crearea vizualizării din codInițializarea proprietăților, adăugarea subview-urilor
init(coder:)Încărcarea din Storyboard/XIBDeserializarea și configurarea inițială
layoutSubviews()La modificarea frame-uluiRecalcularea geometriei elementelor copil
draw(_:)La prima apariție sau după setNeedsDisplay()Desenarea conținutului prin Core Graphics
didMoveToSuperview()După adăugarea în ierarhieConfigurarea finală, pornirea animațiilor

Toate metodele sunt apelate automat de sistem și dezvoltatorul nu trebuie să le apeleze manual. Excepție — setNeedsDisplay(), care semnalează sistemului necesitatea reapelării lui draw(_:).

Suprascrierea draw(_:) pentru desenare

draw(_:) — metoda cheie pentru desenarea personalizată în Custom UIView. În interiorul ei, dezvoltatorul obține acces la CGContext (contextul grafic) și poate desena linii, forme, text și imagini folosind Core Graphics.

Sistemul apelează draw(_:) automat la prima apariție a vizualizării pe ecran. Reapelarea este inițiată prin setNeedsDisplay(), care marchează vizualizarea ca necesitând redesenare. Important: nu apelați draw(_:) direct — aceasta strică mecanismul de cache și reduce performanța.

swift
override func draw(_ rect: CGRect) {
    guard let context = UIGraphicsGetCurrentContext() else { return }

    // Umplerea fundalului
    context.setFillColor(UIColor.systemBlue.cgColor)
    context.fill(rect)

    // Desenarea unui cerc
    context.setStrokeColor(UIColor.white.cgColor)
    context.setLineWidth(4.0)
    let circleRect = rect.insetBy(dx: 20, dy: 20)
    context.strokeEllipse(in: circleRect)
}

În acest exemplu, draw(_:) umple fundalul cu culoare albastră și desenează un cerc alb cu o margine de 20 pixeli de la margini. Fiecare apel draw(_:) trebuie să fie idempotent — apelarea repetată cu aceiași parametri trebuie să dea același rezultat.

Reguli pentru un draw(_:) eficient

Apple recomandă minimizarea muncii în interiorul draw(_:) — creați UIBezierPath în avans, stocați în cache imaginile și nu executați calcule grele. Dacă vizualizarea este statică, luați în considerare utilizarea UIImageView cu o imagine redată în locul redesenării constante.

CALayer versus draw(_:): ce să alegeți

CALayer — este stratul subiacent care gestionează conținutul vizual al UIView. Multe sarcini de desenare personalizată pot fi rezolvate prin configurarea proprietăților CALayer fără a suprascrie draw(_:), ceea ce este semnificativ mai performant.

Conform Apple Engineering (2024), operațiile la nivelul CALayer se execută pe GPU, în timp ce draw(_:) funcționează prin randare CPU Core Graphics. Pentru animații și tranziții fluide este preferabilă utilizarea CALayer și CABasicAnimation.

ScenariuAbordare recomandatăPerformanță
Colțuri rotunjitelayer.cornerRadiusGPU, mare
Umbre și gradienteCAGradientLayer, shadowPathGPU, mare
Forme arbitrareCAShapeLayer cu UIBezierPathGPU, mare
Grafică complexădraw(_:) cu Core GraphicsCPU, medie
Text cu formatare personalizatăCATextLayer sau draw(_:)Depinde de volum

Utilizați CAShapeLayer pentru desenarea formelor vectoriale cu animație — este accelerat hardware și suportă animația path, strokeStart și strokeEnd fără a apela draw(_:).

Optimizarea performanței Custom UIView

Performanța Custom UIView influențează direct fluiditatea animațiilor și impresia generală a aplicației. Problemele principale apar din cauza apelurilor excesive ale draw(_:), a aranjării neoptimale a subview-urilor și a lipsei de cache.

Evitați redesenările inutile

Fiecare apel setNeedsDisplay() duce la redesenarea completă a vizualizării. Utilizați setNeedsDisplay(_:) cu specificarea unui dreptunghi concret, dacă modificările au afectat doar o parte a vizualizării. Pentru proprietățile CALayer (backgroundColor, cornerRadius, shadow) redesenarea nu este necesară — acestea se actualizează la nivel GPU.

Stocarea în cache a conținutului randat

Dacă conținutul Custom UIView se schimbă rar, randați-l o dată în UIGraphicsImageRenderer și salvați-l ca UIImage. La următoarea redesenare, utilizați draw(at:) pentru a afișa imaginea din cache — aceasta este de zeci de ori mai rapid decât redesenarea prin Core Graphics.

swift
func renderToImage() -> UIImage {
    let renderer = UIGraphicsImageRenderer(size: bounds.size)
    return renderer.image { ctx in
        drawHierarchy(in: bounds, afterScreenUpdates: true)
    }
}

Utilizați shouldRasterize pentru straturi statice

Proprietatea shouldRasterize a CALayer activează stocarea în cache a reprezentării rasterizate a stratului. Activați-o pentru vizualizări statice cu transparență și umbre — reduce încărcarea compositing-ului. Dezactivați-o pentru vizualizări animate: la fiecare modificare cache-ul se resetează, iar rasterizarea doar înrăutățește performanța.

Întrebări frecvente

Este obligatorie suprascrierea draw(_:) în Custom UIView?

Nu, draw(_:) este necesar doar la desenarea personalizată prin Core Graphics. Dacă vizualizarea este alcătuită din subview-uri standard (UILabel, UIImageView) și utilizează CALayer, suprascrierea draw(_:) nu este necesară — aceasta chiar va îmbunătăți performanța.

Cum se adaugă Custom UIView în Storyboard?

Plasați un UIView obișnuit pe canvas, în Identity Inspector specificați clasa dvs. în câmpul Class. Dacă clasa este marcată cu @IBDesignable, modificările se vor afișa în timp real direct în Storyboard.

Care este diferența dintre init(frame:) și init(coder:)?

init(frame:) este apelat la crearea programatică a vizualizării — transmiteți un CGRect cu poziția și dimensiunea. init(coder:) este apelat la deserializarea din Storyboard sau XIB. Pentru funcționarea corectă, ambele trebuie implementate, altfel vizualizarea va da eroare la încărcarea din Interface Builder.

De ce nu se apelează draw(_:)?

Cea mai frecventă cauză — vizualizarea are frame zero (lățimea sau înălțimea sunt zero). Sistemul nu apelează draw(_:) pentru vizualizări cu dimensiuni zero. Verificați frame-ul în layoutSubviews() și asigurați-vă că vizualizarea a fost adăugată în ierarhie cu constrângeri corecte.

Cum se actualizează conținutul Custom UIView fără redesenare completă?

Utilizați CALayer pentru proprietățile care suportă animația pe GPU (position, opacity, transform). Pentru actualizarea parțială a draw(_:) aplicați setNeedsDisplay(_:) cu CGRect al zonei de modificare — sistemul va redesena doar zona specificată, nu întreaga vizualizare.

Concluzii

  • Custom UIView — subclasă UIView cu metode suprascrise pentru desenare personalizată, utilizată când componentele standard UIKit sunt insuficiente
  • draw(_:) — metodă pentru desenare personalizată prin Core Graphics, apelată automat de sistem; apelul direct este interzis
  • CALayer — modalitatea preferată pentru grafică accelerată pe GPU (umbre, rotunjiri, forme), alternativă la draw(_:) cu performanță mai mare
  • init(frame:) și init(coder:) — inițializatori obligatorii, implementarea ambilor este necesară pentru funcționarea corectă din cod și Storyboard
  • setNeedsDisplay() — semnal pentru sistem pentru reapelarea draw(_:); utilizați supraîncărcarea cu CGRect pentru redesenare parțială
  • @IBDesignable — atribut pentru previzualizarea live a Custom UIView în Interface Builder, simplifică dezvoltarea vizuală
  • Pentru grafică statică stocați rezultatul în cache prin UIGraphicsImageRenderer și desenați imaginea gata făcută — reduce încărcarea CPU

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.

Discutați proiectul

Citiți și