Vizualizări personalizate și desenare în dezvoltarea mobilă: esența, ce API-uri și cum funcționează

Autor: IT Sectr Publicat: 2026-08-01 Timp de citire: 11 min

Vizualizările personalizate sunt baza interfeței unice a oricărei aplicații mobile. Vizualizările personalizate în aplicațiile mobile vă permit să creați propria grafică, animații și elemente indisponibile în componentele standard. Potrivit Apple Developer, 2025, drawRect rămâne metoda principală de desenare personalizată în dezvoltarea mobilă iOS. Pe Android, onDraw cu Canvas joacă același rol, iar în Flutter — CustomPainter.

Puncte cheie

  • Vizualizări personalizate — componente definite de utilizator cu propria logică de desenare, dimensiune și comportament în aplicațiile mobile.
  • drawRect — metoda UIView pe iOS pentru desenare personalizată prin Core Graphics și CGContext.
  • onDraw — metoda View pe Android pentru desenare prin Canvas și Paint cu sistemul de măsurare onMeasure.
  • CustomPainter — clasa Flutter pentru desenare pe Canvas cu metodele paint și shouldRepaint.
  • Măsurare — procesul de determinare a dimensiunilor Vizualizării prin sizeThatFits pe iOS, onMeasure pe Android și computeDryLayout în Flutter.

Ce sunt vizualizările personalizate și de ce sunt necesare în aplicațiile mobile

Vizualizările personalizate sunt componente de interfață definite de utilizator care suprascriu metodele standard de desenare și măsurare pentru a crea grafică unică. Grafice, animații, diagrame, elemente de chat personalizate și măști AR — acestea sunt scenarii tipice de utilizare a vizualizărilor personalizate în aplicațiile mobile. Componentele UI standard (Button, TextView, Label) acoperă 80% din sarcini, dar restul de 20% necesită control total asupra desenării în dezvoltarea mobilă. Desenarea în dezvoltarea mobilă este o abilitate care diferențiază un dezvoltator junior de un senior.

Când sunt justificate vizualizările personalizate

Vizualizările personalizate în aplicațiile mobile sunt necesare pentru grafică 2D unică, animații complexe, diagrame și vizualizare a datelor. Dacă UIKit standard nu oferă elementul necesar — se creează o vizualizare personalizată. În aplicațiile mobile, vizualizările personalizate sunt utilizate pentru bare de progres, butoane personalizate, umpleri gradient, pictograme animate și pânze pentru desenare cu degetul. Este important să nu abuzați — pentru stiluri simple, este suficient să configurați componentele standard prin API-ul de aspect.

Vizualizări personalizate pe iOS: drawRect și Core Graphics

Pe iOS, vizualizările personalizate sunt create prin moștenirea UIView și suprascrierea metodei drawRect. drawRect este apelat la primul randament și după fiecare apel setNeedsDisplay(). În interiorul drawRect, dezvoltatorul obține un CGContext prin UIGraphicsGetCurrentContext() — o pânză pentru linii, forme, gradiente și text. Core Graphics (Quartz 2D) este un motor de randare de nivel scăzut pe CPU care oferă control total asupra fiecărui pixel. UIBezierPath este un înveliș convenabil pentru crearea de căi cu sintaxă concisă.

swift
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: CGContext, CGGradient și transformări

Core Graphics oferă CGContext — o pânză pentru toate operațiile de desenare. CGGradient creează gradiente liniare și radiale cu suport pentru CGColorSpace (sRGB, Display P3). Transformările sunt efectuate prin CGAffineTransform — o matrice 3x3 pentru rotire, scalare și translație. CGContextTranslateCTM, CGContextRotateCTM și CGContextScaleCTM modifică sistemul de coordonate. Core Graphics rulează pe CPU, astfel încât grafica complexă poate încărca procesorul — utilizați Metal pentru accelerare GPU.

UIBezierPath pentru crearea formelor

UIBezierPath este un înveliș orientat pe obiecte peste CGPath. Metoda addArc(withCenter:radius:startAngle:endAngle:clockwise:) creează arcuri și cercuri, addCurve creează curbe Bézier. Căile suportă operații de uniune, intersectare și scădere prin addClip. UIBezierPath este convenabil pentru măști personalizate (maskView), căi de decupare și forme complexe — stele, inimi, pictograme personalizate.

Vizualizări personalizate pe Android: onDraw și Canvas

Pe Android, o vizualizare personalizată extinde View cu onDraw(Canvas) suprascris. Canvas conține toate metodele de desenare în dezvoltarea mobilă: drawCircle, drawRect, drawLine, drawText, drawBitmap, drawPath și drawRoundRect. Paint configurează parametrii — culoare, grosimea liniei, stil (FILL, STROKE, FILL_AND_STROKE), anti-aliasing (isAntiAlias) și dimensiunea textului. onDraw este apelat la fiecare invalidate() și nu trebuie să conțină operații grele — toate calculele sunt stocate în cache.

kotlin
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 și animații pe Android

Path pe Android este echivalentul lui UIBezierPath: addCircle, addRect, addOval, lineTo, cubicTo și quadTo. PathMeasure calculează lungimea căii și coordonatele în orice punct — util pentru animarea mișcării unui obiect de-a lungul unei căi. Pentru animații, se utilizează ValueAnimator cu invalidate() în callback. Animatorul poate schimba culoarea, raza, poziția — orice proprietate care afectează desenarea. Vizualizările personalizate pe Android suportă, de asemenea, StateListDrawable și animated-vector pentru animație prin XML.

Shader și gradiente în Canvas

Gradienturile pe Android se setează prin Shader — LinearGradient, RadialGradient și SweepGradient. Shader se atribuie lui Paint prin paint.setShader(shader). LinearGradient generează un gradient liniar între două puncte cu poziții de culoare opționale. RadialGradient — radial de la centru la margini. SweepGradient — conic în jurul unui punct central. Shader.TileMode (CLAMP, REPEAT, MIRROR) definește comportamentul dincolo de limitele zonei.

CustomPainter în Flutter: desenare pe Canvas

Flutter utilizează CustomPainter — o clasă cu metodele paint(Canvas canvas, Size size) și shouldRepaint. Canvas în Flutter oferă aceleași metode ca în Android: drawCircle, drawRect, drawLine, drawPath, drawParagraph și drawImage. Paint în Flutter configurează culoarea, grosimea, stilul și anti-aliasing-ul. Flutter nu folosește drawRect sau onDraw — toată desenarea se face prin CustomPainter, încorporat în widgetul CustomPaint.

dart
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 și RepaintBoundary

shouldRepaint determină dacă CustomPainter trebuie redesenat. Returnați true numai când se modifică datele care afectează randarea — culoare, dimensiune, datele graficului. RepaintBoundary izolează redesenearea într-un strat separat — utilizați pentru widgeturi care se schimbă rar. Flutter nu are setNeedsDisplay sau invalidate — redesenearea este declanșată prin setState sau ValueNotifier cu ascultarea modificărilor.

Gradiente și transformări în Flutter

Flutter suportă LinearGradient, RadialGradient și SweepGradient — aceleași tipuri ca în Android. Gradient creează un Shader pentru Paint prin createShader(Rect bounds). Transformările sunt efectuate prin canvas.rotate, canvas.scale, canvas.translate și canvas.skew. Flutter utilizează o matrice de transformare 4x4 (Matrix4) pentru widgetul Transform. Animațiile de desenare în Flutter se fac cu AnimationController împreună cu setState pentru redesenearea CustomPainter.

Măsurarea vizualizărilor personalizate: metodele sizeThatFits, onMeasure și computeDryLayout

Măsurarea corectă a vizualizărilor personalizate este baza comportamentului previzibil al interfeței. Pe iOS, dimensiunea Vizualizării se determină prin sizeThatFits și intrinsicContentSize. sizeThatFits returnează dimensiunea optimă pentru constrângerile date. intrinsicContentSize — dimensiunea naturală a conținutului fără constrângeri externe. Pe Android, măsurarea este implementată în onMeasure cu parametrii MeasureSpec (UNSPECIFIED, EXACTLY, AT_MOST). În Flutter, dimensiunea este transmisă lui paint(Canvas, Size) și poate fi calculată prin computeDryLayout sau LayoutBuilder.

sizeThatFits și intrinsicContentSize pe iOS

intrinsicContentSize returnează un CGSize — dimensiunea naturală a Vizualizării pe baza conținutului său. setContentHuggingPriority și setContentCompressionResistancePriority controlează comportamentul în timpul întinderii și comprimării. sizeThatFits este apelat de sistem pentru a calcula dimensiunea în Auto Layout. Pentru vizualizări personalizate, suprascrieți intrinsicContentSize dacă componenta dvs. are o dimensiune naturală — de exemplu, un cerc ar trebui să fie întotdeauna 100x100.

onMeasure și MeasureSpec pe Android

onMeasure acceptă widthMeasureSpec și heightMeasureSpec. MeasureSpec conține mod și dimensiune: UNSPECIFIED (fără constrângeri, Vizualizarea își alege dimensiunea), EXACTLY (dimensiune exactă de la părinte), AT_MOST (dimensiune maximă). setMeasuredDimension(width, height) salvează rezultatul măsurării. La schimbarea datelor, apelați requestLayout() pentru remăsurare. ViewGroup-urile imbricate necesită suprascrierea onLayout pentru aranjarea elementelor copil.

PlatformăMetodă de măsurareApel la schimbareReturnare
iOSsizeThatFits / intrinsicContentSizesetNeedsLayout / invalidateIntrinsicContentSizeCGSize
AndroidonMeasure / setMeasuredDimensionrequestLayout / invalidatevoid (salvează dimensiunea)
FluttercomputeDryLayoutsetState / LayoutBuilderSize

computeDryLayout în Flutter

computeDryLayout este o metodă RenderObject pentru calcularea dimensiunii fără un ciclu complet de layout. LayoutBuilder.getSize — o alternativă pentru obținerea spațiului disponibil în metoda build. În Flutter, dimensiunea pânzei este transmisă lui paint ca Size și nu necesită măsurare separată — CustomPainter desenează în limitele transmise. Cu toate acestea, pentru RenderObject-uri personalizate, trebuie să suprascrieți performLayout și computeDryLayout.

Întrebări frecvente

Ce este drawRect pe iOS și când este apelat?

drawRect este o metodă UIView pentru desenare personalizată prin Core Graphics. Este apelată la primul randament al Vizualizării și după fiecare apel setNeedsDisplay(). Utilizați CGContext în interiorul drawRect pentru linii, forme și text.

Cum să desenați pe Android folosind Canvas?

Creați o clasă care extinde View, suprascrieți onDraw(Canvas canvas) și utilizați API-ul Canvas: drawCircle, drawRect, drawPath. Paint configurează culoarea, grosimea și stilul. Pentru actualizare, apelați invalidate().

Ce este CustomPainter în Flutter?

CustomPainter este o clasă Flutter pentru desenare personalizată pe Canvas. Implementați metodele paint(Canvas, Size) și shouldRepaint. Este plasat prin widgetul CustomPaint. Flutter nu are drawRect — toată desenarea se face prin CustomPainter.

Cum să măsurați dimensiunea unei vizualizări personalizate?

Pe iOS utilizați sizeThatFits și intrinsicContentSize. Pe Android — onMeasure cu MeasureSpec. În Flutter, dimensiunea este transmisă lui paint(Canvas, Size) sau calculată prin computeDryLayout. Fiecare platformă folosește propria metodă de măsurare.

Când să utilizați vizualizări personalizate în locul componentelor standard?

Vizualizările personalizate sunt necesare pentru grafică unică, animații, diagrame și elemente care nu pot fi implementate cu UIKit sau View standard. Pentru stiluri simple, este suficient să configurați componentele standard — nu complicați arhitectura inutil.

Rezumat

  • Vizualizări personalizate — baza interfețelor unice pentru diagrame, animații și elemente non-standard în aplicațiile mobile.
  • drawRect — metodă iOS pentru desenare prin Core Graphics cu CGContext și UIBezierPath.
  • onDraw — metodă Android pentru desenare prin Canvas și Paint cu suport Path și Shader.
  • CustomPainter — clasă Flutter pentru desenare pe Canvas cu shouldRepaint și RepaintBoundary.
  • Măsurare — validare a dimensiunilor prin sizeThatFits (iOS), onMeasure (Android) și computeDryLayout (Flutter).
  • Desenarea în dezvoltarea mobilă urmează un model unificat pe toate platformele: obțineți un context, configurați stilurile și desenați primitive.
  • Stocați în cache obiectele de desenare (Paint, Path) — nu le creați în interiorul drawRect, onDraw sau paint pentru performanță stabilă.

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