Viste personalizzate e disegno nello sviluppo mobile: essenza, quali API e come funziona

Autore: IT Sectr Pubblicato: 2026-08-01 Tempo di lettura: 11 min

Le viste personalizzate sono la base dell'interfaccia unica di qualsiasi app mobile. Le viste personalizzate nelle app mobili permettono di creare grafica, animazioni ed elementi propri non disponibili nei componenti standard. Secondo Apple Developer, 2025, drawRect rimane il metodo principale di disegno personalizzato nello sviluppo mobile iOS. Su Android, onDraw con Canvas svolge lo stesso ruolo, e in Flutter — CustomPainter.

Punti chiave

  • Viste personalizzate — componenti definiti dall'utente con logica propria di disegno, dimensione e comportamento nelle app mobili.
  • drawRect — metodo UIView su iOS per disegno personalizzato tramite Core Graphics e CGContext.
  • onDraw — metodo View su Android per disegno tramite Canvas e Paint con il sistema di misura onMeasure.
  • CustomPainter — classe Flutter per disegnare su Canvas con i metodi paint e shouldRepaint.
  • Misura — processo di determinazione delle dimensioni della Vista tramite sizeThatFits su iOS, onMeasure su Android e computeDryLayout in Flutter.

Cosa sono le viste personalizzate e perché servono nelle app mobili

Le viste personalizzate sono componenti d'interfaccia definiti dall'utente che sovrascrivono i metodi standard di disegno e misura per creare grafica unica. Grafici, animazioni, diagrammi, elementi chat personalizzati e maschere AR — questi sono scenari tipici di utilizzo delle viste personalizzate nelle app mobili. I componenti UI standard (Button, TextView, Label) coprono l'80% delle attività, ma il restante 20% richiede il controllo completo sul disegno nello sviluppo mobile. Il disegno nello sviluppo mobile è un'abilità che distingue uno sviluppatore junior da un senior.

Quando le viste personalizzate sono giustificate

Le viste personalizzate nelle app mobili sono necessarie per grafica 2D unica, animazioni complesse, grafici e visualizzazione dei dati. Se l'UIKit standard non fornisce l'elemento necessario — viene creata una vista personalizzata. Nelle app mobili, le viste personalizzate vengono utilizzate per barre di progresso, pulsanti personalizzati, riempimenti sfumati, icone animate e canvas per disegnare con il dito. È importante non abusarne — per stili semplici basta configurare i componenti standard tramite l'API di aspetto.

Viste personalizzate su iOS: drawRect e Core Graphics

Su iOS, le viste personalizzate vengono create ereditando da UIView e sovrascrivendo il metodo drawRect. drawRect viene chiamato al primo render e dopo ogni chiamata a setNeedsDisplay(). All'interno di drawRect, lo sviluppatore ottiene un CGContext tramite UIGraphicsGetCurrentContext() — una tela per linee, forme, gradienti e testo. Core Graphics (Quartz 2D) è un motore di rendering di basso livello su CPU che offre il controllo completo su ogni pixel. UIBezierPath è un wrapper conveniente per creare percorsi con sintassi concisa.

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 e trasformazioni

Core Graphics fornisce CGContext — una tela per tutte le operazioni di disegno. CGGradient crea gradienti lineari e radiali con supporto di CGColorSpace (sRGB, Display P3). Le trasformazioni vengono eseguite tramite CGAffineTransform — una matrice 3x3 per rotazione, ridimensionamento e traslazione. CGContextTranslateCTM, CGContextRotateCTM e CGContextScaleCTM modificano il sistema di coordinate. Core Graphics funziona su CPU, quindi la grafica complessa può caricare il processore — utilizzare Metal per l'accelerazione GPU.

UIBezierPath per creare forme

UIBezierPath è un wrapper orientato agli oggetti su CGPath. Il metodo addArc(withCenter:radius:startAngle:endAngle:clockwise:) crea archi e cerchi, addCurve crea curve di Bézier. I percorsi supportano operazioni di unione, intersezione e sottrazione tramite addClip. UIBezierPath è conveniente per maschere personalizzate (maskView), percorsi di ritaglio e forme complesse — stelle, cuori, icone personalizzate.

Viste personalizzate su Android: onDraw e Canvas

Su Android, una vista personalizzata estende View con onDraw(Canvas) sovrascritto. Canvas contiene tutti i metodi di disegno nello sviluppo mobile: drawCircle, drawRect, drawLine, drawText, drawBitmap, drawPath e drawRoundRect. Paint configura i parametri — colore, spessore della linea, stile (FILL, STROKE, FILL_AND_STROKE), anti-alias (isAntiAlias) e dimensione del testo. onDraw viene chiamato ad ogni invalidate() e non deve contenere operazioni pesanti — tutti i calcoli vengono memorizzati nella 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 e animazioni su Android

Path su Android è l'equivalente di UIBezierPath: addCircle, addRect, addOval, lineTo, cubicTo e quadTo. PathMeasure calcola la lunghezza del percorso e le coordinate in qualsiasi punto — utile per animare il movimento di un oggetto lungo un percorso. Per le animazioni, si utilizza ValueAnimator con invalidate() nel callback. L'animatore può cambiare colore, raggio, posizione — qualsiasi proprietà che influenzi il disegno. Le viste personalizzate su Android supportano anche StateListDrawable e animated-vector per animazioni tramite XML.

Shader e gradienti in Canvas

I gradienti su Android vengono impostati tramite Shader — LinearGradient, RadialGradient e SweepGradient. Shader viene assegnato a Paint tramite paint.setShader(shader). LinearGradient genera un gradiente lineare tra due punti con posizioni di colore opzionali. RadialGradient — radiale dal centro ai bordi. SweepGradient — conico attorno a un punto centrale. Shader.TileMode (CLAMP, REPEAT, MIRROR) definisce il comportamento oltre i limiti dell'area.

CustomPainter in Flutter: disegno su Canvas

Flutter utilizza CustomPainter — una classe con i metodi paint(Canvas canvas, Size size) e shouldRepaint. Canvas in Flutter fornisce gli stessi metodi che in Android: drawCircle, drawRect, drawLine, drawPath, drawParagraph e drawImage. Paint in Flutter configura colore, spessore, stile e anti-alias. Flutter non usa drawRect né onDraw — tutto il disegno avviene tramite CustomPainter, incorporato nel widget 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 e RepaintBoundary

shouldRepaint determina se CustomPainter deve essere ridisegnato. Restituisci true solo quando cambiano i dati che influenzano il rendering — colore, dimensione, dati del grafico. RepaintBoundary isola il ridisegno in un layer separato — usalo per widget che cambiano raramente. Flutter non ha setNeedsDisplay o invalidate — il ridisegno viene attivato tramite setState o ValueNotifier con ascolto delle modifiche.

Gradienti e trasformazioni in Flutter

Flutter supporta LinearGradient, RadialGradient e SweepGradient — gli stessi tipi che in Android. Gradient crea uno Shader per Paint tramite createShader(Rect bounds). Le trasformazioni vengono eseguite tramite canvas.rotate, canvas.scale, canvas.translate e canvas.skew. Flutter utilizza una matrice di trasformazione 4x4 (Matrix4) per il widget Transform. Le animazioni di disegno in Flutter vengono realizzate con AnimationController in combinazione con setState per ridisegnare CustomPainter.

Misura delle viste personalizzate: metodi sizeThatFits, onMeasure e computeDryLayout

La corretta misura delle viste personalizzate è la base del comportamento prevedibile dell'interfaccia. Su iOS, la dimensione della Vista viene determinata tramite sizeThatFits e intrinsicContentSize. sizeThatFits restituisce la dimensione ottimale per i vincoli dati. intrinsicContentSize — la dimensione naturale del contenuto senza vincoli esterni. Su Android, la misura viene implementata in onMeasure con parametri MeasureSpec (UNSPECIFIED, EXACTLY, AT_MOST). In Flutter, la dimensione viene passata a paint(Canvas, Size) e può essere calcolata tramite computeDryLayout o LayoutBuilder.

sizeThatFits e intrinsicContentSize su iOS

intrinsicContentSize restituisce un CGSize — la dimensione naturale della Vista basata sul suo contenuto. setContentHuggingPriority e setContentCompressionResistancePriority controllano il comportamento durante l'allungamento e la compressione. sizeThatFits viene chiamato dal sistema per calcolare la dimensione in Auto Layout. Per viste personalizzate, sovrascrivi intrinsicContentSize se il tuo componente ha una dimensione naturale — ad esempio, un cerchio dovrebbe essere sempre 100x100.

onMeasure e MeasureSpec su Android

onMeasure accetta widthMeasureSpec e heightMeasureSpec. MeasureSpec contiene modalità e dimensione: UNSPECIFIED (senza vincoli, la Vista sceglie la propria dimensione), EXACTLY (dimensione esatta dal genitore), AT_MOST (dimensione massima). setMeasuredDimension(width, height) salva il risultato della misura. Quando i dati cambiano, chiama requestLayout() per rimisurare. I ViewGroup annidati richiedono la sovrascrittura di onLayout per disporre gli elementi figli.

PiattaformaMetodo di misuraChiamata al cambiamentoRitorno
iOSsizeThatFits / intrinsicContentSizesetNeedsLayout / invalidateIntrinsicContentSizeCGSize
AndroidonMeasure / setMeasuredDimensionrequestLayout / invalidatevoid (salva dimensione)
FluttercomputeDryLayoutsetState / LayoutBuilderSize

computeDryLayout in Flutter

computeDryLayout è un metodo RenderObject per calcolare la dimensione senza un ciclo di layout completo. LayoutBuilder.getSize — un'alternativa per ottenere lo spazio disponibile nel metodo build. In Flutter, la dimensione della tela viene passata a paint come Size e non richiede misura separata — CustomPainter disegna entro i limiti passati. Tuttavia, per RenderObject personalizzati, è necessario sovrascrivere performLayout e computeDryLayout.

Domande frequenti

Cos'è drawRect su iOS e quando viene chiamato?

drawRect è un metodo UIView per il disegno personalizzato tramite Core Graphics. Viene chiamato al primo render della Vista e dopo ogni chiamata a setNeedsDisplay(). Usa CGContext all'interno di drawRect per linee, forme e testo.

Come disegnare su Android usando Canvas?

Crea una classe che estende View, sovrascrivi onDraw(Canvas canvas) e usa l'API Canvas: drawCircle, drawRect, drawPath. Paint configura colore, spessore e stile. Per aggiornare, chiama invalidate().

Cos'è CustomPainter in Flutter?

CustomPainter è una classe Flutter per il disegno personalizzato su Canvas. Implementa i metodi paint(Canvas, Size) e shouldRepaint. Viene posizionato tramite il widget CustomPaint. Flutter non ha drawRect — tutto il disegno avviene tramite CustomPainter.

Come misurare la dimensione di una vista personalizzata?

Su iOS usa sizeThatFits e intrinsicContentSize. Su Android — onMeasure con MeasureSpec. In Flutter, la dimensione viene passata a paint(Canvas, Size) o calcolata tramite computeDryLayout. Ogni piattaforma usa il proprio metodo di misura.

Quando usare viste personalizzate invece dei componenti standard?

Le viste personalizzate sono necessarie per grafica unica, animazioni, grafici ed elementi che non possono essere implementati con UIKit o View standard. Per stili semplici, basta configurare i componenti standard — non complicare l'architettura inutilmente.

Riepilogo

  • Viste personalizzate — base di interfacce uniche per grafici, animazioni ed elementi non standard nelle app mobili.
  • drawRect — metodo iOS per disegno tramite Core Graphics con CGContext e UIBezierPath.
  • onDraw — metodo Android per disegno tramite Canvas e Paint con supporto di Path e Shader.
  • CustomPainter — classe Flutter per disegno su Canvas con shouldRepaint e RepaintBoundary.
  • Misura — validazione delle dimensioni tramite sizeThatFits (iOS), onMeasure (Android) e computeDryLayout (Flutter).
  • Il disegno nello sviluppo mobile segue un modello unificato su tutte le piattaforme: ottenere un contesto, configurare gli stili e disegnare primitive.
  • Memorizza nella cache gli oggetti di disegno (Paint, Path) — non crearli all'interno di drawRect, onDraw o paint per prestazioni stabili.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto