[{"data":1,"prerenderedAt":22},["ShallowReactive",2],{"articolo-custom-painting-in-flutter-disegnare-con-custompaint-e-canvas":3,"comments-article-custom-painting-in-flutter-disegnare-con-custompaint-e-canvas":21},{"id":4,"title":5,"slug":6,"excerpt":7,"body":8,"cover_image":9,"video_url":10,"status":11,"published_at":12,"meta_title":13,"meta_description":14,"category":15,"author":19},22,"Custom Painting in Flutter: disegnare con CustomPaint e Canvas","custom-painting-in-flutter-disegnare-con-custompaint-e-canvas","Impara a usare CustomPaint, CustomPainter e l'API Canvas per disegnare grafica personalizzata in Flutter: forme, percorsi, gradienti e grafici da zero.","## Perché serve CustomPaint\n\nFlutter offre un ricco catalogo di widget pronti all'uso, ma prima o poi ci si imbatte in un requisito che nessun widget standard risolve: un grafico personalizzato, una firma digitale, un indicatore circolare animato o forme geometriche complesse. In questi casi la risposta è `CustomPaint`, che ci dà accesso diretto al `Canvas`, lo stesso strato di disegno su cui poggia l'intero framework.\n\n## I tre attori principali\n\nIl disegno custom ruota attorno a tre elementi:\n\n- **CustomPaint**: il widget che ospita il disegno e lo inserisce nell'albero dei widget.\n- **CustomPainter**: la classe dove definiamo *cosa* disegnare, tramite il metodo `paint`.\n- **Canvas**: l'oggetto che espone i metodi di disegno (linee, rettangoli, percorsi, testo).\n\n## Il primo CustomPainter\n\nPer disegnare bisogna estendere `CustomPainter` e implementare due metodi: `paint` e `shouldRepaint`.\n\n```dart\nclass CerchioPainter extends CustomPainter {\n  final Color colore;\n\n  CerchioPainter({required this.colore});\n\n  @override\n  void paint(Canvas canvas, Size size) {\n    final paint = Paint()\n      ..color = colore\n      ..style = PaintingStyle.fill;\n\n    final centro = Offset(size.width \u002F 2, size.height \u002F 2);\n    final raggio = size.width \u002F 3;\n\n    canvas.drawCircle(centro, raggio, paint);\n  }\n\n  @override\n  bool shouldRepaint(covariant CerchioPainter oldDelegate) {\n    return oldDelegate.colore != colore;\n  }\n}\n```\n\nIl parametro `Size` rappresenta lo spazio disponibile assegnato al `CustomPaint`. Usarlo per calcolare le coordinate rende il disegno responsivo.\n\n## Inserire il painter nell'interfaccia\n\n```dart\nCustomPaint(\n  size: const Size(200, 200),\n  painter: CerchioPainter(colore: Colors.indigo),\n)\n```\n\nSe `CustomPaint` ha un figlio, il disegno funge da sfondo; per disegnare *sopra* il figlio si usa il parametro `foregroundPainter`.\n\n## L'oggetto Paint\n\n`Paint` configura l'aspetto di ciò che disegniamo. Le proprietà più usate sono:\n\n- `color`: il colore.\n- `style`: `PaintingStyle.fill` (riempimento) o `PaintingStyle.stroke` (contorno).\n- `strokeWidth`: spessore della linea.\n- `strokeCap`: stile delle estremità delle linee.\n- `shader`: per applicare gradienti.\n- `isAntiAlias`: smussatura dei bordi (attiva di default).\n\n```dart\nfinal paint = Paint()\n  ..style = PaintingStyle.stroke\n  ..strokeWidth = 4\n  ..strokeCap = StrokeCap.round\n  ..shader = const LinearGradient(\n    colors: [Colors.blue, Colors.purple],\n  ).createShader(Rect.fromLTWH(0, 0, 200, 200));\n```\n\n## Disegnare percorsi con Path\n\nPer forme libere si usa `Path`, che permette di concatenare segmenti, curve e archi. Ecco un esempio che disegna un triangolo:\n\n```dart\n@override\nvoid paint(Canvas canvas, Size size) {\n  final paint = Paint()..color = Colors.teal;\n\n  final path = Path()\n    ..moveTo(size.width \u002F 2, 0)\n    ..lineTo(size.width, size.height)\n    ..lineTo(0, size.height)\n    ..close();\n\n  canvas.drawPath(path, paint);\n}\n```\n\nLe curve di Bézier (`quadraticBezierTo` e `cubicTo`) consentono di creare forme morbide, utili per onde, fumetti o bordi arrotondati personalizzati.\n\n## Un esempio pratico: grafico a barre\n\nMettiamo insieme i concetti per disegnare un semplice grafico a barre.\n\n```dart\nclass BarChartPainter extends CustomPainter {\n  final List\u003Cdouble> valori;\n\n  BarChartPainter(this.valori);\n\n  @override\n  void paint(Canvas canvas, Size size) {\n    final paint = Paint()..color = Colors.amber;\n    final massimo = valori.reduce((a, b) => a > b ? a : b);\n    final larghezzaBarra = size.width \u002F (valori.length * 2);\n\n    for (var i = 0; i \u003C valori.length; i++) {\n      final altezza = (valori[i] \u002F massimo) * size.height;\n      final x = (i * 2 + 0.5) * larghezzaBarra;\n      final rect = Rect.fromLTWH(\n        x,\n        size.height - altezza,\n        larghezzaBarra,\n        altezza,\n      );\n      canvas.drawRRect(\n        RRect.fromRectAndRadius(rect, const Radius.circular(4)),\n        paint,\n      );\n    }\n  }\n\n  @override\n  bool shouldRepaint(covariant BarChartPainter oldDelegate) {\n    return oldDelegate.valori != valori;\n  }\n}\n```\n\n## Disegnare testo sul canvas\n\nIl `Canvas` non disegna testo direttamente: serve `TextPainter`.\n\n```dart\nfinal textPainter = TextPainter(\n  text: const TextSpan(\n    text: '42%',\n    style: TextStyle(color: Colors.black, fontSize: 18),\n  ),\n  textDirection: TextDirection.ltr,\n)..layout();\n\ntextPainter.paint(canvas, const Offset(10, 10));\n```\n\n## Animare un CustomPainter\n\nCombinando `CustomPainter` con un `AnimationController` si ottengono animazioni fluide. Basta passare il valore animato al painter e ridisegnare a ogni frame.\n\n```dart\nAnimatedBuilder(\n  animation: controller,\n  builder: (context, _) {\n    return CustomPaint(\n      size: const Size(200, 200),\n      painter: ProgressPainter(progresso: controller.value),\n    );\n  },\n)\n```\n\nIn questo modo `shouldRepaint` riceve a ogni tick il nuovo valore e Flutter ridisegna solo l'area interessata.\n\n## Considerazioni sulle performance\n\nIl disegno custom è efficiente, ma alcune accortezze fanno la differenza:\n\n- Implementa correttamente `shouldRepaint`: ritorna `true` solo quando qualcosa cambia davvero.\n- Evita di creare oggetti `Paint` o `Path` complessi a ogni chiamata di `paint` se possono essere precalcolati.\n- Per disegni statici e costosi valuta `RepaintBoundary` per isolare l'area dai rebuild circostanti.\n- Usa `canvas.save()` e `canvas.restore()` quando applichi trasformazioni (rotazioni, traslazioni) per non propagarle al resto del disegno.\n\n## Conclusione\n\n`CustomPaint` apre le porte a interfacce che vanno oltre i widget standard: grafici, indicatori, illustrazioni e animazioni vettoriali. Padroneggiare l'API `Canvas` e l'oggetto `Path` ti permette di realizzare qualsiasi elemento visivo immaginabile, mantenendo le ottime performance del motore di rendering di Flutter.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Farticles\u002F190ab403-0e16-45f3-9a91-bcb247102860.jpg",null,"published","2026-06-26T04:00:38+00:00","Custom Painting in Flutter: CustomPaint e Canvas","Guida pratica a CustomPaint, CustomPainter e Canvas in Flutter: disegna forme, percorsi, gradienti, testo e grafici personalizzati con ottime performance.",{"id":16,"name":17,"slug":18},1,"Guide","guide",{"id":16,"name":20},"Flutter Bot",[],1785219604537]