Az egyedi nézetek képezik bármely mobilalkalmazás egyedi felületének alapját. Az egyedi nézetek a mobilalkalmazásokban lehetővé teszik saját grafika, animációk és elemek létrehozását, amelyek nem érhetők el a szabványos komponensekben. A Apple Developer, 2025 szerint a drawRect továbbra is az egyedi rajzolás elsődleges módszere az iOS mobilfejlesztésben. Androidon az onDraw a Canvas-szal tölti be ugyanazt a szerepet, Flutterben pedig a CustomPainter.
Főbb pontok
Az egyedi nézetek felhasználó által meghatározott interfész komponensek, amelyek felülírják a szabványos rajzolási és mérési metódusokat egyedi grafika létrehozásához. Grafikonok, animációk, diagramok, egyedi csevegőelemek és AR maszkok — ezek tipikus alkalmazási forgatókönyvei az egyedi nézeteknek a mobilalkalmazásokban. A szabványos UI komponensek (Button, TextView, Label) a feladatok 80%-át fedik le, de a fennmaradó 20% teljes kontrollt igényel a rajzolás felett a mobilfejlesztésben. A rajzolás a mobilfejlesztésben olyan készség, amely megkülönbözteti a junior fejlesztőt a senior-tól.
Az egyedi nézetek a mobilalkalmazásokban egyedi 2D grafikához, összetett animációkhoz, diagramokhoz és adatvizualizációhoz szükségesek. Ha a szabványos UIKit nem biztosítja a szükséges elemet — egy egyedi Nézet jön létre. A mobilalkalmazásokban az egyedi nézeteket folyamatjelző sávokhoz, egyedi gombokhoz, színátmenetes kitöltésekhez, animált ikonokhoz és ujjal rajzoló vásznakhoz használják. Fontos, hogy ne éljenek vissza vele — egyszerű stílusokhoz elegendő a szabványos komponenseket a Megjelenés API-n keresztül konfigurálni.
iOS-en az egyedi nézetek a UIView-ből való örökléssel és a drawRect metódus felülírásával jönnek létre. A drawRect az első rendereléskor és minden setNeedsDisplay() hívás után meghívásra kerül. A drawRect-en belül a fejlesztő egy CGContext-et kap az UIGraphicsGetCurrentContext() segítségével — egy vásznat vonalakhoz, alakzatokhoz, színátmenetekhez és szöveghez. A Core Graphics (Quartz 2D) egy alacsony szintű CPU-alapú renderelő motor, amely teljes kontrollt biztosít minden egyes pixel felett. Az UIBezierPath egy kényelmes burkolóobjektum útvonalak létrehozásához tömör szintaxissal.
class CircleView: UIView {
private var fillColor: UIColor = .systemBlue
override func drawRect(_ rect: CGRect) {
guard let ctx = UIGraphicsGetCurrentContext() else { return }
ctx.setFillColor(fillColor.cgColor)
ctx.addEllipse(in: bounds.insetBy(dx: 4, dy: 4))
ctx.drawPath(using: .fill)
}
func updateColor(_ newColor: UIColor) {
fillColor = newColor
setNeedsDisplay()
}
}
A Core Graphics biztosítja a CGContext-et — egy vásznat az összes rajzolási művelethez. A CGGradient lineáris és radiális színátmeneteket hoz létre a CGColorSpace (sRGB, Display P3) támogatásával. A transzformációk a CGAffineTransform segítségével történnek — egy 3x3-as mátrix forgatáshoz, méretezéshez és eltoláshoz. A CGContextTranslateCTM, CGContextRotateCTM és CGContextScaleCTM módosítják a koordináta-rendszert. A Core Graphics a CPU-n fut, így az összetett grafika terhelheti a processzort — használja a Metal-t a GPU-gyorsításhoz.
Az UIBezierPath egy objektumorientált burkoló a CGPath felett. Az addArc(withCenter:radius:startAngle:endAngle:clockwise:) metódus íveket és köröket hoz létre, az addCurve Bézier-görbéket hoz létre. Az útvonalak támogatják az egyesítés, metszet és kivonás műveleteket az addClip segítségével. Az UIBezierPath kényelmes egyedi maszkokhoz (maskView), vágóútvonalakhoz és összetett alakzatokhoz — csillagok, szívek, egyedi ikonok.
Androidon egy egyedi Nézet a View-t terjeszti ki felülírt onDraw(Canvas) segítségével. A Canvas tartalmazza az összes rajzolási metódust a mobilfejlesztésben: drawCircle, drawRect, drawLine, drawText, drawBitmap, drawPath és drawRoundRect. A Paint konfigurálja a paramétereket — szín, vonalvastagság, stílus (FILL, STROKE, FILL_AND_STROKE), élsimítás (isAntiAlias) és szövegméret. Az onDraw minden invalidate() alkalmával meghívásra kerül, és nem tartalmazhat nehéz műveleteket — az összes számítás gyorsítótárba kerül.
class CustomCircleView(context: Context, attrs: AttributeSet?)
: View(context, attrs) {
private val paint = Paint().apply {
style = Paint.Style.FILL
color = Color.BLUE
isAntiAlias = true
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val cx = width / 2f
val cy = height / 2f
val radius = minOf(cx, cy) - 4f
canvas.drawCircle(cx, cy, radius, paint)
}
}
A Path Androidon az UIBezierPath megfelelője: addCircle, addRect, addOval, lineTo, cubicTo és quadTo. A PathMeasure kiszámítja az útvonal hosszát és a koordinátákat bármely pontban — hasznos egy objektum útvonal menti mozgásának animálásához. Az animációkhoz a ValueAnimator használatos invalidate() hívással a visszahívásban. Az animátor változtathatja a színt, sugarat, pozíciót — bármely tulajdonságot, amely befolyásolja a rajzolást. Az egyedi nézetek Androidon támogatják a StateListDrawable és animated-vector elemeket is az animációhoz XML segítségével.
A színátmenetek Androidon a Shader segítségével állíthatók be — LinearGradient, RadialGradient és SweepGradient. A Shader a paint.setShader(shader) segítségével kerül hozzárendelésre a Paint-hez. A LinearGradient lineáris színátmenetet hoz létre két pont között opcionális színpozíciókkal. A RadialGradient — radiális a középponttól a szélek felé. A SweepGradient — kúpos egy középpont körül. A Shader.TileMode (CLAMP, REPEAT, MIRROR) meghatározza a viselkedést a terület határain túl.
A Flutter a CustomPainter-t használja — egy osztályt a paint(Canvas canvas, Size size) és shouldRepaint metódusokkal. A Canvas a Flutterben ugyanazokat a metódusokat biztosítja, mint Androidon: drawCircle, drawRect, drawLine, drawPath, drawParagraph és drawImage. A Paint a Flutterben konfigurálja a színt, vastagságot, stílust és élsimítást. A Flutter nem használ drawRect vagy onDraw metódust — minden rajzolás a CustomPainter-en keresztül történik, amely a CustomPaint widget-be van ágyazva.
class CirclePainter extends CustomPainter {
final Color color;
CirclePainter({required this.color});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = color
..style = PaintingStyle.fill
..isAntiAlias = true;
final radius = size.shortestSide / 2 - 4;
canvas.drawCircle(size.center(Offset.zero), radius, paint);
}
@override
bool shouldRepaint(CirclePainter oldDelegate) =>
oldDelegate.color != color;
}
A shouldRepaint meghatározza, hogy a CustomPainter-t újra kell-e rajzolni. Csak akkor adjon vissza true értéket, ha a renderelést befolyásoló adatok megváltoznak — szín, méret, diagram adatok. A RepaintBoundary elkülöníti az újrarajzolást egy külön rétegbe — használja olyan widgetekhez, amelyek ritkán változnak. A Flutter-ben nincs setNeedsDisplay vagy invalidate — az újrarajzolás a setState vagy a változásokat figyelő ValueNotifier segítségével indul el.
A Flutter támogatja a LinearGradient, RadialGradient és SweepGradient típusokat — ugyanazokat, mint Androidon. A Gradient egy Shader-t hoz létre a Paint számára a createShader(Rect bounds) segítségével. A transzformációk a canvas.rotate, canvas.scale, canvas.translate és canvas.skew segítségével történnek. A Flutter egy 4x4-es transzformációs mátrixot (Matrix4) használ a Transform widgethez. A rajzolási animációk a Flutter-ben az AnimationController segítségével készülnek a setState-vel kombinálva a CustomPainter újrarajzolásához.
Az egyedi nézetek helyes mérése a kiszámítható interfész viselkedés alapja. iOS-en a Nézet mérete a sizeThatFits és intrinsicContentSize segítségével kerül meghatározásra. A sizeThatFits visszaadja az optimális méretet az adott korlátozásokhoz. Az intrinsicContentSize — a tartalom természetes mérete külső korlátozások nélkül. Androidon a mérés az onMeasure-ben valósul meg a MeasureSpec paraméterekkel (UNSPECIFIED, EXACTLY, AT_MOST). Flutterben a méret átadásra kerül a paint(Canvas, Size) metódusnak, és kiszámítható a computeDryLayout vagy LayoutBuilder segítségével.
Az intrinsicContentSize egy CGSize értéket ad vissza — a Nézet természetes méretét a tartalma alapján. A setContentHuggingPriority és setContentCompressionResistancePriority szabályozza a viselkedést nyújtás és tömörítés során. A sizeThatFits-t a rendszer hívja meg a méret kiszámításához az Auto Layout-ben. Egyedi nézetek esetén írja felül az intrinsicContentSize-t, ha komponense természetes mérettel rendelkezik — például egy körnek mindig 100x100-nak kell lennie.
Az onMeasure elfogadja a widthMeasureSpec és heightMeasureSpec paramétereket. A MeasureSpec módot és méretet tartalmaz: UNSPECIFIED (korlátozások nélkül, a Nézet maga választja meg méretét), EXACTLY (pontos méret a szülőtől), AT_MOST (maximális méret). A setMeasuredDimension(width, height) elmenti a mérés eredményét. Adatok változásakor hívja a requestLayout()-ot az újbóli méréshez. A beágyazott ViewGroup-ok megkövetelik az onLayout felülírását a gyermek elemek elrendezéséhez.
| Platform | Mérési metódus | Hívás változáskor | Visszatérés |
|---|---|---|---|
| iOS | sizeThatFits / intrinsicContentSize | setNeedsLayout / invalidateIntrinsicContentSize | CGSize |
| Android | onMeasure / setMeasuredDimension | requestLayout / invalidate | void (méretet ment) |
| Flutter | computeDryLayout | setState / LayoutBuilder | Size |
A computeDryLayout egy RenderObject metódus a méret kiszámításához teljes elrendezési ciklus nélkül. LayoutBuilder.getSize — egy alternatíva a rendelkezésre álló hely lekérésére a build metódusban. Flutterben a vászon mérete Size-ként kerül átadásra a paint-nek, és nem igényel külön mérést — a CustomPainter az átadott határokon belül rajzol. Azonban egyedi RenderObject-ok esetén felül kell írnia a performLayout és computeDryLayout metódusokat.
Gyakran Ismételt Kérdések
drawRect egy UIView metódus egyedi rajzoláshoz a Core Graphics segítségével. A Nézet első renderelésekor és minden setNeedsDisplay() hívás után hívódik meg. Használja a CGContext-et a drawRect-en belül vonalakhoz, alakzatokhoz és szöveghez.
Hozzon létre egy osztályt, amely kiterjeszti a View-t, írja felül a onDraw(Canvas canvas) metódust, és használja a Canvas API-t: drawCircle, drawRect, drawPath. A Paint konfigurálja a színt, vastagságot és stílust. A frissítéshez hívja az invalidate()-et.
CustomPainter egy Flutter osztály egyedi rajzoláshoz a Canvas-on. Implementálja a paint(Canvas, Size) és shouldRepaint metódusokat. A CustomPaint widget-en keresztül helyezhető el. A Flutter-ben nincs drawRect — minden rajzolás a CustomPainter-en keresztül történik.
iOS-en használja a sizeThatFits és intrinsicContentSize metódusokat. Androidon — az onMeasure-t a MeasureSpec-szel. Flutterben a méret átadásra kerül a paint(Canvas, Size) metódusnak, vagy kiszámítható a computeDryLayout segítségével. Minden platform a saját mérési metódusát használja.
Egyedi nézetek szükségesek egyedi grafikához, animációkhoz, diagramokhoz és olyan elemekhez, amelyek nem valósíthatók meg szabványos UIKit vagy View segítségével. Egyszerű stílusokhoz elegendő a szabványos komponenseket konfigurálni — ne bonyolítsa szükségtelenül az architektúrát.
Ö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.