Explorando o Custom Painter no Flutter para Desenhos Personalizados

Introdução

O Flutter é conhecido por sua flexibilidade em criar interfaces personalizadas. Uma das ferramentas mais poderosas para isso é o Custom Painter, que permite desenhar diretamente no canvas, criando formas, animações e gráficos completamente personalizados.

Neste tutorial, vamos explorar como usar o CustomPainter para criar desenhos personalizados no Flutter, abordando cenários práticos e dicas avançadas.

1. O que é o CustomPainter?

O CustomPainter é uma classe abstrata que permite implementar métodos como paint para desenhar diretamente no canvas, usando objetos como Paint, Path e Canvas. Ele é usado para criar gráficos vetoriais, animações e muito mais.

2. Criando um Custom Painter Básico

Vamos começar com um exemplo básico de como desenhar um círculo:


import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Custom Painter Example')),
        body: Center(
          child: CustomPaint(
            size: const Size(200, 200),
            painter: CirclePainter(),
          ),
        ),
      ),
    );
  }
}

class CirclePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill;

    canvas.drawCircle(
      Offset(size.width / 2, size.height / 2),
      size.width / 2,
      paint,
    );
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

O código acima desenha um círculo azul preenchido no centro do canvas.

3. Adicionando Complexidade com Path

Você pode criar formas complexas com o Path. Aqui está um exemplo de como desenhar uma estrela:


class StarPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.orange
      ..style = PaintingStyle.fill;

    final path = Path();
    path.moveTo(size.width / 2, 0);
    path.lineTo(size.width * 0.4, size.height * 0.6);
    path.lineTo(0, size.height * 0.6);
    path.lineTo(size.width * 0.3, size.height);
    path.lineTo(size.width * 0.2, size.height * 1.4);
    path.lineTo(size.width / 2, size.height * 1.1);
    path.close();

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

4. Animações com Custom Painter

Você pode usar o CustomPainter com animações para criar gráficos dinâmicos. Aqui está um exemplo de como animar um círculo:


class AnimatedCircle extends StatefulWidget {
  @override
  _AnimatedCircleState createState() => _AnimatedCircleState();
}

class _AnimatedCircleState extends State
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    )..repeat(reverse: true);

    _animation = Tween(begin: 50, end: 150).animate(_controller);
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation,
      builder: (context, child) {
        return CustomPaint(
          size: const Size(200, 200),
          painter: AnimatedCirclePainter(radius: _animation.value),
        );
      },
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

class AnimatedCirclePainter extends CustomPainter {
  final double radius;

  AnimatedCirclePainter({required this.radius});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.fill;

    canvas.drawCircle(
      Offset(size.width / 2, size.height / 2),
      radius,
      paint,
    );
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

5. Dicas e Boas Práticas

  • Use shouldRepaint com sabedoria para otimizar o desempenho.
  • Divida sua lógica de desenho em funções reutilizáveis.
  • Evite cálculos caros dentro do método paint.

Publicar comentário