Vlastní zobrazení jsou základem jedinečného rozhraní každé mobilní aplikace. Vlastní zobrazení v mobilních aplikacích umožňují vytvářet vlastní grafiku, animace a prvky nedostupné ve standardních komponentách. Podle Apple Developer, 2025 zůstává drawRect hlavní metodou vlastního kreslení v mobilním vývoji na iOS. Na Androidu hraje stejnou roli onDraw s Canvasem a ve Flutter — CustomPainter.
Hlavní body
Vlastní zobrazení jsou uživatelsky definované komponenty rozhraní, které přepisují standardní metody kreslení a měření pro vytváření jedinečné grafiky. Grafy, animace, diagramy, vlastní prvky chatu a AR masky — to jsou typické scénáře použití vlastních zobrazení v mobilních aplikacích. Standardní UI komponenty (Button, TextView, Label) pokrývají 80% úkolů, ale zbývajících 20% vyžaduje úplnou kontrolu nad kreslením v mobilním vývoji. Kreslení v mobilním vývoji je dovednost, která odlišuje junior vývojáře od seniora.
Vlastní zobrazení v mobilních aplikacích jsou potřebná pro jedinečnou 2D grafiku, složité animace, grafy a vizualizaci dat. Pokud standardní UIKit neposkytuje požadovaný prvek — vytvoří se vlastní zobrazení. V mobilních aplikacích se vlastní zobrazení používají pro ukazatele průběhu, vlastní tlačítka, přechodové výplně, animované ikony a plátna pro kreslení prstem. Je důležité to nepřehánět — pro jednoduché styly stačí nakonfigurovat standardní komponenty přes API vzhledu.
Na iOS se vlastní zobrazení vytvářejí děděním z UIView a přepsáním metody drawRect. drawRect se volá při prvním vykreslení a po každém volání setNeedsDisplay(). Uvnitř drawRect získá vývojář CGContext přes UIGraphicsGetCurrentContext() — plátno pro čáry, tvary, přechody a text. Core Graphics (Quartz 2D) je nízkoúrovňový vykreslovací engine na CPU, který poskytuje úplnou kontrolu nad každým pixelem. UIBezierPath je pohodlný obal pro vytváření cest se stručnou syntaxí.
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()
}
}
Core Graphics poskytuje CGContext — plátno pro všechny kreslicí operace. CGGradient vytváří lineární a radiální přechody s podporou CGColorSpace (sRGB, Display P3). Transformace se provádějí přes CGAffineTransform — matice 3x3 pro otáčení, škálování a posun. CGContextTranslateCTM, CGContextRotateCTM a CGContextScaleCTM mění souřadnicový systém. Core Graphics běží na CPU, takže složitá grafika může zatěžovat procesor — pro GPU akceleraci použijte Metal.
UIBezierPath je objektově orientovaný obal nad CGPath. Metoda addArc(withCenter:radius:startAngle:endAngle:clockwise:) vytváří oblouky a kruhy, addCurve vytváří Bézierovy křivky. Cesty podporují operace sjednocení, průniku a odečítání přes addClip. UIBezierPath je vhodný pro vlastní masky (maskView), ořezové cesty a složité tvary — hvězdy, srdce, vlastní ikony.
Na Androidu vlastní zobrazení rozšiřuje View s přepsaným onDraw(Canvas). Canvas obsahuje všechny metody kreslení v mobilním vývoji: drawCircle, drawRect, drawLine, drawText, drawBitmap, drawPath a drawRoundRect. Paint konfiguruje parametry — barvu, tloušťku čáry, styl (FILL, STROKE, FILL_AND_STROKE), vyhlazování (isAntiAlias) a velikost textu. onDraw se volá při každém invalidate() a neměl by obsahovat těžké operace — všechny výpočty se ukládají do mezipaměti.
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)
}
}
Path na Androidu je ekvivalentem UIBezierPath: addCircle, addRect, addOval, lineTo, cubicTo a quadTo. PathMeasure vypočítává délku cesty a souřadnice v libovolném bodě — užitečné pro animaci pohybu objektu podél cesty. Pro animace se používá ValueAnimator s invalidate() ve zpětném volání. Animátor může měnit barvu, poloměr, pozici — jakoukoli vlastnost ovlivňující kreslení. Vlastní zobrazení na Androidu také podporují StateListDrawable a animated-vector pro animace přes XML.
Přechody na Androidu se nastavují přes Shader — LinearGradient, RadialGradient a SweepGradient. Shader se přiřazuje k Paint přes paint.setShader(shader). LinearGradient generuje lineární přechod mezi dvěma body s volitelnými pozicemi barev. RadialGradient — radiální od středu k okrajům. SweepGradient — kuželový kolem středového bodu. Shader.TileMode (CLAMP, REPEAT, MIRROR) určuje chování za hranicemi oblasti.
Flutter používá CustomPainter — třídu s metodami paint(Canvas canvas, Size size) a shouldRepaint. Canvas ve Flutter poskytuje stejné metody jako v Androidu: drawCircle, drawRect, drawLine, drawPath, drawParagraph a drawImage. Paint ve Flutter konfiguruje barvu, tloušťku, styl a vyhlazování. Flutter nepoužívá drawRect ani onDraw — veškeré kreslení probíhá přes CustomPainter, vložený do widgetu CustomPaint.
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;
}
shouldRepaint určuje, zda je třeba CustomPainter překreslit. Vracejte true pouze při změně dat ovlivňujících vykreslování — barva, velikost, data grafu. RepaintBoundary izoluje překreslování do samostatné vrstvy — používejte pro widgety, které se mění zřídka. Flutter nemá setNeedsDisplay ani invalidate — překreslování se spouští přes setState nebo ValueNotifier s nasloucháním změn.
Flutter podporuje LinearGradient, RadialGradient a SweepGradient — stejné typy jako v Androidu. Gradient vytváří Shader pro Paint přes createShader(Rect bounds). Transformace se provádějí přes canvas.rotate, canvas.scale, canvas.translate a canvas.skew. Flutter používá transformační matici 4x4 (Matrix4) pro widget Transform. Animace kreslení ve Flutter se vytvářejí pomocí AnimationController v kombinaci se setState pro překreslení CustomPainter.
Správné měření vlastních zobrazení je základem předvídatelného chování rozhraní. Na iOS se velikost Zobrazení určuje přes sizeThatFits a intrinsicContentSize. sizeThatFits vrací optimální velikost pro daná omezení. intrinsicContentSize — přirozená velikost obsahu bez vnějších omezení. Na Androidu je měření implementováno v onMeasure s parametry MeasureSpec (UNSPECIFIED, EXACTLY, AT_MOST). Ve Flutter se velikost předává do paint(Canvas, Size) a lze ji vypočítat přes computeDryLayout nebo LayoutBuilder.
intrinsicContentSize vrací CGSize — přirozenou velikost Zobrazení na základě jeho obsahu. setContentHuggingPriority a setContentCompressionResistancePriority řídí chování při natahování a stlačování. sizeThatFits volá systém pro výpočet velikosti v Auto Layout. Pro vlastní zobrazení přepište intrinsicContentSize, pokud má váš komponent přirozenou velikost — například kruh by měl být vždy 100x100.
onMeasure přijímá widthMeasureSpec a heightMeasureSpec. MeasureSpec obsahuje režim a velikost: UNSPECIFIED (bez omezení, Zobrazení si volí vlastní velikost), EXACTLY (přesná velikost od rodiče), AT_MOST (maximální velikost). setMeasuredDimension(width, height) ukládá výsledek měření. Při změně dat zavolejte requestLayout() pro přeměření. Vnořené ViewGroup vyžadují přepsání onLayout pro uspořádání podřízených prvků.
| Platforma | Metoda měření | Volání při změně | Návrat |
|---|---|---|---|
| iOS | sizeThatFits / intrinsicContentSize | setNeedsLayout / invalidateIntrinsicContentSize | CGSize |
| Android | onMeasure / setMeasuredDimension | requestLayout / invalidate | void (ukládá velikost) |
| Flutter | computeDryLayout | setState / LayoutBuilder | Size |
computeDryLayout je metoda RenderObject pro výpočet velikosti bez úplného cyklu rozvržení. LayoutBuilder.getSize — alternativa pro získání dostupného prostoru v metodě build. Ve Flutter se velikost plátna předává do paint jako Size a nevyžaduje samostatné měření — CustomPainter kreslí v předaných hranicích. Pro vlastní RenderObject je však třeba přepsat performLayout a computeDryLayout.
Často kladené otázky
drawRect je metoda UIView pro vlastní kreslení přes Core Graphics. Volá se při prvním vykreslení Zobrazení a po každém volání setNeedsDisplay(). Použijte CGContext uvnitř drawRect pro čáry, tvary a text.
Vytvořte třídu rozšiřující View, přepište onDraw(Canvas canvas) a použijte Canvas API: drawCircle, drawRect, drawPath. Paint konfiguruje barvu, tloušťku a styl. Pro aktualizaci zavolejte invalidate().
CustomPainter je třída Flutter pro vlastní kreslení na Canvas. Implementujte metody paint(Canvas, Size) a shouldRepaint. Umísťuje se přes widget CustomPaint. Flutter nemá drawRect — veškeré kreslení probíhá přes CustomPainter.
Na iOS použijte sizeThatFits a intrinsicContentSize. Na Androidu — onMeasure s MeasureSpec. Ve Flutter se velikost předává do paint(Canvas, Size) nebo se vypočítá přes computeDryLayout. Každá platforma používá vlastní metodu měření.
Vlastní zobrazení jsou potřebná pro jedinečnou grafiku, animace, grafy a prvky, které nelze implementovat standardním UIKit nebo View. Pro jednoduché styly stačí nakonfigurovat standardní komponenty — nekomplikujte architekturu zbytečně.
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í.