Custom UIView — az UIKit UIView komponensének egy alosztálya, amelyben a fejlesztő felülírja az életciklus- és rajzolási metódusokat egyedi vizuális elemek létrehozásához. A szabványos UIView-ek (UIButton, UILabel, UIImageView) a legtöbb tipikus forgatókönyvet lefedik, de amikor nem szabványos grafikára, animációra vagy interaktivitásra van szükség, nem lehet megkerülni az egyedi UIView létrehozását. Az Apple Documentation (2025) szerint az egyedi UIView-ek az App Store alkalmazások 68%-ában használatosak, ahol nem szabványos interfész megoldások fordulnak elő. Ez a megközelítés teljes kontrollt biztosít a rajzolás, az érintéskezelés és az elemek elrendezése felett a nézeten belül.
Főbb pontok
Custom UIView — egy egyedi osztály, amely a UIView-ből öröklődik, és amelyben a fejlesztő felülírja a szabványos metódusokat saját megjelenítési és interakciós logikájának megvalósításához. Az UIKit számos kész komponenst tartalmaz, de ezek nem fednek le minden forgatókönyvet: animált grafikonok, nem szabványos kapcsolók, kézzel rajzoláshoz használt vászon, játékelemek vagy adatvizualizáció egyedi megvalósítást igényelnek.
Az Apple akkor javasolja a Custom UIView létrehozását, amikor a szabványos komponensek nem tudják biztosítani a szükséges funkcionalitást, vagy amikor ugyanaz az egyedi elem az alkalmazás több helyén is használatos. A WWDC 2024 szerint az egyedi nézetek átlagosan az összes UIView 15-20%-át teszik ki egy közepes méretű projektben.
Az egyedi UIView grafikonok és diagramok (vonalak és alakzatok rajzolása Core Graphics segítségével), nem szabványos folyamatjelzők, animált hátterek, ujjal rajzoláshoz használt elemek, valamint valós idejű adatvizualizáció építésére használható. Mindegyik esetben a fejlesztő teljes hozzáféréssel rendelkezik a CGContext-hez, és bármilyen geometriát lerajzolhat.
Ha az elem összeállítható szabványos UIKit komponensekből (UIButton, UIImageView, UILabel) Auto Layout és tulajdonságok beállításával — akkor a UIView alosztály létrehozása felesleges. Az Apple azt javasolja, hogy először próbálja ki a kész nézetek kompozícióját, és csak akkor térjen át az egyedi rajzolásra, ha a funkcionalitás nem elegendő.
Az egyedi UIView létrehozása a UIView-ből öröklődő osztály deklarálásával és a kötelező inicializálók megvalósításával kezdődik. A minimális megvalósítás tartalmazza a init(frame:)-et a kódból történő létrehozáshoz és a init(coder:)-t a Storyboard-ból vagy XIB-ből történő betöltéshez.
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
}
}
A setupView() metódusban a kezdeti tulajdonságok kerülnek beállításra: átlátszó háttér, rétegbeállítások. Ha a nézet megjelenik az Interface Builder-ben, érdemes hozzáadni a @IBDesignable és @IBInspectable attribútumokat az élő előnézethez.
Custom UIView a rendszer által egy meghatározott sorrendben meghívott életciklus metódusok sorozatán keresztül kerül vezérlésre. Ennek a ciklusnak a megértése kritikus fontosságú a nézet helyes konfigurálásához és rajzolásához.
| Metódus | Mikor hívódik | Cél |
|---|---|---|
| init(frame:) | Nézet létrehozása kódból | Tulajdonságok inicializálása, alnézetek hozzáadása |
| init(coder:) | Betöltés Storyboard/XIB-ből | Deszerializáció és kezdeti konfiguráció |
| layoutSubviews() | A keret megváltozásakor | Gyermek elemek geometriájának újraszámítása |
| draw(_:) | Első megjelenéskor vagy setNeedsDisplay() után | Tartalom rajzolása Core Graphics segítségével |
| didMoveToSuperview() | A hierarchiába való hozzáadás után | Végső konfiguráció, animációk elindítása |
Minden metódus automatikusan meghívódik a rendszer által, és a fejlesztőnek nem kell azokat manuálisan meghívnia. Kivétel — a setNeedsDisplay(), amely jelzi a rendszernek a draw(_:) újbóli meghívásának szükségességét.
draw(_:) — a kulcsmetódus az egyedi rajzoláshoz a Custom UIView-ben. Belül a fejlesztő hozzáférést kap a CGContext-hez (grafikus környezet), és vonalakat, alakzatokat, szöveget és képeket rajzolhat a Core Graphics segítségével.
A rendszer automatikusan meghívja a draw(_:)-t a nézet első képernyőn való megjelenésekor. Az újbóli meghívást a setNeedsDisplay() kezdeményezi, amely megjelöli a nézetet, mint újrarajzolást igénylőt. Fontos: ne hívja meg közvetlenül a draw(_:)-t — ez tönkreteszi a gyorsítótárazási mechanizmust és csökkenti a teljesítményt.
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
// Háttér kitöltése
context.setFillColor(UIColor.systemBlue.cgColor)
context.fill(rect)
// Kör rajzolása
context.setStrokeColor(UIColor.white.cgColor)
context.setLineWidth(4.0)
let circleRect = rect.insetBy(dx: 20, dy: 20)
context.strokeEllipse(in: circleRect)
}
Ebben a példában a draw(_:) kék színnel tölti ki a hátteret és egy fehér kört rajzol 20 pixel margóval a szélektől. Minden draw(_:) hívásnak idempotensnek kell lennie — az azonos paraméterekkel történő ismételt hívásnak ugyanazt az eredményt kell adnia.
Az Apple a draw(_:) belsejében végzett munka minimalizálását javasolja — hozza létre előre a UIBezierPath-et, gyorsítótárazza a képeket, és ne végezzen nehéz számításokat. Ha a nézet statikus, fontolja meg a UIImageView használatát egy előre renderelt képpel az állandó újrarajzolás helyett.
CALayer — az alatta lévő réteg, amely a UIView vizuális tartalmát kezeli. Az egyedi rajzolás számos feladata megoldható a CALayer tulajdonságainak konfigurálásával a draw(_:) felülírása nélkül, ami jelentősen hatékonyabb.
Az Apple Engineering (2024) szerint a CALayer szintű műveletek a GPU-n hajtódnak végre, míg a draw(_:) a CPU Core Graphics renderelésén keresztül működik. Animációkhoz és sima átmenetekhez a CALayer és a CABasicAnimation használata előnyösebb.
| Forgatókönyv | Ajánlott megközelítés | Teljesítmény |
|---|---|---|
| Lekerekített sarkok | layer.cornerRadius | GPU, magas |
| Árnyékok és gradiensek | CAGradientLayer, shadowPath | GPU, magas |
| Tetszőleges alakzatok | CAShapeLayer UIBezierPath-pel | GPU, magas |
| Összetett grafika | draw(_:) Core Graphics-szal | CPU, közepes |
| Szöveg egyedi formázással | CATextLayer vagy draw(_:) | Mennyiségtől függ |
Használja a CAShapeLayer-t vektoros alakzatok rajzolásához animációval — hardveresen gyorsított, és támogatja a path, strokeStart és strokeEnd animációját a draw(_:) meghívása nélkül.
A Custom UIView teljesítménye közvetlenül befolyásolja az animációk simaságát és az alkalmazás általános felhasználói élményét. A fő problémák a draw(_:) túlzott meghívásából, az alnézetek nem optimális elrendezéséből és a gyorsítótárazás hiányából adódnak.
Minden setNeedsDisplay() hívás a nézet teljes újrarajzolásához vezet. Használja a setNeedsDisplay(_:)-t egy adott téglalap megadásával, ha a változtatások csak a nézet egy részét érintik. A CALayer tulajdonságokhoz (backgroundColor, cornerRadius, shadow) nincs szükség újrarajzolásra — ezek GPU szinten frissülnek.
Ha a Custom UIView tartalma ritkán változik, renderelje le egyszer a UIGraphicsImageRenderer-ben, és mentse el UIImage-ként. A következő újrarajzoláskor használja a draw(at:)-t a gyorsítótárazott kép megjelenítéséhez — ez több tízszer gyorsabb, mint a Core Graphics-on keresztüli újrarajzolás.
func renderToImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(size: bounds.size)
return renderer.image { ctx in
drawHierarchy(in: bounds, afterScreenUpdates: true)
}
}
A CALayer shouldRasterize tulajdonsága bekapcsolja a réteg raszteres megjelenítésének gyorsítótárazását. Kapcsolja be statikus nézetekhez átlátszósággal és árnyékokkal — ez csökkenti a kompozitálási terhelést. Kapcsolja ki animált nézetekhez: minden változásnál a gyorsítótár alaphelyzetbe áll, és a raszterizáció csak rontja a teljesítményt.
Gyakran ismételt kérdések
Nem, a draw(_:) csak egyedi rajzoláshoz szükséges a Core Graphics-on keresztül. Ha a nézet szabványos alnézetekből (UILabel, UIImageView) áll és CALayer-t használ, a draw(_:) felülírása nem szükséges — ez még javít is a teljesítményen.
Helyezzen egy szokásos UIView-t a vászonra, az Identity Inspector-ban adja meg az osztályát a Class mezőben. Ha az osztály @IBDesignable jelöléssel rendelkezik, a változtatások valós időben, közvetlenül a Storyboard-ban jelennek meg.
Az init(frame:) a nézet programozott létrehozásakor hívódik — Ön egy CGRect-et ad át pozícióval és mérettel. Az init(coder:) a Storyboard-ból vagy XIB-ből történő deszerializációkor hívódik. A helyes működéshez mindkettőt implementálni kell, különben a nézet összeomlik az Interface Builder-ből való betöltéskor.
A leggyakoribb ok — a nézet nulla kerettel rendelkezik (a szélesség vagy a magasság nulla). A rendszer nem hívja meg a draw(_:)-t nulla méretű nézetek esetén. Ellenőrizze a keretet a layoutSubviews()-ban, és győződjön meg arról, hogy a nézet megfelelő korlátokkal lett hozzáadva a hierarchiához.
Használja a CALayer-t azokhoz a tulajdonságokhoz, amelyek támogatják a GPU-s animációt (position, opacity, transform). A draw(_:) részleges frissítéséhez alkalmazza a setNeedsDisplay(_:)-t a változtatási terület CGRect-jével — a rendszer csak a megadott területet rajzolja újra, nem a teljes nézetet.
Összefoglalás
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