Flutter University
  • πŸ‘‹Welcome to Flutter University
  • Learn Flutter
    • πŸš—Basics
      • 🧺Dart Basics
      • πŸš›Setup & Installation
      • 🐣Hello Flutter
      • πŸŒ‰Widgets
      • ⛸️Basic State Management
      • πŸ‡ΎπŸ‡ΉBasic Layout and Styling
      • 🐝Basic Interactivity
      • πŸ›£οΈNavigation
      • πŸͺ„Working with Assets
    • πŸš…Intermediate
      • 🎯Deeper into Dart
      • ⭐More on State Management
      • πŸ“ƒForm Handling
      • πŸ—ΌNetworking
      • πŸŽ‡Persistence
      • πŸ§™β€β™‚οΈAnimations
      • πŸ§ͺTesting
      • πŸ“¦Package Management
    • ✈️Professional
      • πŸŽ“Advanced Animations
      • 🎨Custom Painters
      • 🐼Continuous Integration/Continuous Deployment (CI/CD)
      • 🎭Performance Profiling
      • πŸ”¬Native Integrations
      • 🌍Accessibility and Localization
      • 🀘Understanding Design Patterns
      • πŸ“šFlutter Architecture
        • The Layer Model
        • Reactive User Interfaces
        • Flutter Widgets
        • The Rendering Process
        • Platform Embedders Overview
        • Integrating with Other Code
        • Support for the Web
  • Tutorials
    • 🌈UI
      • 🏚️Clubhouse Clone
      • πŸ”‰Netflix Clone
    • βš”οΈFull Stack
    • ⛓️Blockchain
    • πŸ€–AI/ML
  • Miscellaneous
    • πŸ–₯️100 Days of Flutter
    • 🎨Join Community
Powered by GitBook
On this page
  • Custom Painting in Flutter 🎨
  • 1. Introduction to CustomPainter πŸ–ŒοΈ
  • 2. Drawing Shapes 🟦
  • 3. Drawing Text πŸ…°οΈ
  • 4. Drawing Images πŸ–ΌοΈ
  • Custom Dial Example:
  • Assignments πŸ“

Was this helpful?

  1. Learn Flutter
  2. Professional

Custom Painters

Creating custom graphics in Flutter can be done with the CustomPainter class, which allows you to draw shapes, text, and images directly onto the screen. The Canvas object provides a wide array of drawing functions to help you create your custom visuals.


Custom Painting in Flutter 🎨

1. Introduction to CustomPainter πŸ–ŒοΈ

CustomPainter allows you to draw directly to the screen. It’s used in conjunction with a CustomPaint widget.

class MyCustomPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    // Your painting code here...
  }

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

2. Drawing Shapes 🟦

Use the Canvas object to draw shapes like circles, rectangles, arcs, and paths.

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

  final rect = Rect.fromLTWH(0, 0, 100, 100);
  canvas.drawRect(rect, paint);
}

3. Drawing Text πŸ…°οΈ

Draw text by first creating a TextPainter, setting the text and style, then painting it onto the canvas.

void paint(Canvas canvas, Size size) {
  final textPainter = TextPainter(
    text: TextSpan(
      text: 'Hello, world!',
      style: TextStyle(color: Colors.black, fontSize: 30),
    ),
    textDirection: TextDirection.ltr,
  );

  textPainter.layout();
  textPainter.paint(canvas, Offset(50, 50));
}

4. Drawing Images πŸ–ΌοΈ

Load images and draw them onto the canvas.

ui.Image image;

void loadImage() async {
  final ByteData data = await rootBundle.load('assets/image.png');
  final List<int> bytes = data.buffer.asUint8List();
  final ui.Codec codec = await ui.instantiateImageCodec(bytes);
  final ui.FrameInfo frameInfo = await codec.getNextFrame();
  image = frameInfo.image;
}

void paint(Canvas canvas, Size size) {
  if (image != null) {
    canvas.drawImage(image, Offset.zero, Paint());
  }
}

Custom Dial Example:

import 'dart:math';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DialScreen(),
    );
  }
}

class DialScreen extends StatefulWidget {
  @override
  _DialScreenState createState() => _DialScreenState();
}

class _DialScreenState extends State<DialScreen> {
  double dialValue = 0.0;

  void _updateDialValue(double value) {
    setState(() {
      dialValue = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Custom Dial Example'),
      ),
      body: Center(
        child: CustomDial(
          value: dialValue,
          onChanged: _updateDialValue,
        ),
      ),
    );
  }
}

class CustomDial extends StatelessWidget {
  final double value;
  final ValueChanged<double> onChanged;

  CustomDial({required this.value, required this.onChanged});

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanUpdate: (details) {
        RenderBox box = context.findRenderObject() as RenderBox;
        Offset position = box.globalToLocal(details.globalPosition);
        final double angle = atan2(position.dy - box.size.height / 2, position.dx - box.size.width / 2);
        final double newValue = angle / (2 * pi) + 0.5;
        onChanged(newValue.clamp(0.0, 1.0));
      },
      child: CustomPaint(
        painter: DialPainter(value),
        size: Size(200, 200),
      ),
    );
  }
}

class DialPainter extends CustomPainter {
  final double value;

  DialPainter(this.value);

  @override
  void paint(Canvas canvas, Size size) {
    double angle = 2 * pi * (value - 0.25);
    Offset center = size.center(Offset.zero);
    double radius = size.width / 2;

    Paint paintLine = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.stroke
      ..strokeWidth = 8.0;

    Paint paintOutline = Paint()
      ..color = Colors.black
      ..style = PaintingStyle.stroke;

    Paint paintKnob = Paint()..color = Colors.black;

    canvas.drawCircle(center, radius, paintOutline);
    canvas.drawLine(center, Offset(center.dx + radius * cos(angle), center.dy + radius * sin(angle)), paintLine);
    canvas.drawCircle(Offset(center.dx + radius * cos(angle), center.dy + radius * sin(angle)), 25, paintKnob);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return oldDelegate != this;
  }
}

In this example:

  • We create a DialScreen widget to hold the current value of the dial and to create a CustomDial widget.

  • The CustomDial widget takes a value and a callback for when the value changes. It creates a GestureDetector to handle drag updates, and a CustomPaint widget to actually draw the dial.

  • Inside the onPanUpdate callback, we calculate the new value of the dial based on the angle of the drag and call onChanged to update the value.

  • We create a DialPainter class that extends CustomPainter, which draws the dial using the current value.

  • The paint method of DialPainter, we draw an outline circle, a line from the centre of the circle to the current position of the dial, and a knob at the end of the line.


Assignments πŸ“

Last updated 12 months ago

Was this helpful?

✈️
🎨