DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Using the Custom Paint widget to Create a Linear Gauge - Part 1
Curtly Critchlow
Curtly Critchlow

Posted on

Using the Custom Paint widget to Create a Linear Gauge - Part 1

Introduction

At the end of this tutorial series you will learn how to use the custom paint widget by creating a Linear Gauge. The custom paint widget allows you to draw and paint directly to the canvas. This is useful when you can't find or combine a pre build widget to meet your needs.

At the end of this series your linear gauge will look like this.

simple linear gauge final

Creating a flutter project

Before we start building a linear gauge, let's create our flutter project. In your terminal run;

$ flutter create linear_gauge
Enter fullscreen mode Exit fullscreen mode

In main.dart delete everything starting from line 7 and replace it with the following.

import 'linear_gauge.dart';
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Linear Gauge',
      home: LinearGauge(maxValue: 100, minValue: 0, actualValue: 75),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Now we have to create the LinearGauge() widget.

How a linear gauge works

From the image in the introduction we can deduce that the gauge need to be provided with a maximum value, a minimum value and an actual value. The gauge then displays the actual value in proportion to the maximum and minimum value.

Let's create our stateful widget to represent this;

$ touch lib/linear_gauge.dart
Enter fullscreen mode Exit fullscreen mode
import 'package:flutter/material.dart';
import 'linear_gauge_custom_painter.dart';

class LinearGauge extends StatefulWidget {
  LinearGauge({
    required this.maxValue,
    required this.minValue,
    required this.actualValue,
    Key? key,
  }) : super(key: key);

  final double maxValue;
  final double minValue;
  final double actualValue;

  @override
  State<LinearGauge> createState() => _LinearGaugeState();
}

class _LinearGaugeState extends State<LinearGauge> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Linear Gauge')),
      body: CustomPaint(
        size: MediaQuery.of(context).size,
        painter: LinearGaugeCustomPainter(),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

You will notice our body property accepts a CustomPaint that takes in a LinearGaugeCustomPainter. This class will be used to draw and paint our linear gauge into existence.

We used MediaQuery.of(context).size to ensure our gauge scales to the device size.

Components of a linear gauge

Before we start painting it is important to breakdown our linear gauge into its components. From the image above we notice that the gauge comprises of;

  1. A main axis - this is the vertical part of the gauge.

  2. Major ticks - This is the long horizontal lines

  3. Minor ticks - This is the short horizontal lines.

  4. Scale - The numbers that the ticks represents.

  5. Pointer - The vertical line that colors the main axis from the minimum value to the actual value.

  6. The actual value indicator - The icon that shows where the actual value is.

  7. The actual Value - The TextPainter that displays the actual value.

$ touch lib/linear_gauge_custom_painter.dart
Enter fullscreen mode Exit fullscreen mode
import 'package:flutter/material.dart';

class LinearGaugeCustomPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    // TODO: implement paint
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    throw UnimplementedError();
  }
}
Enter fullscreen mode Exit fullscreen mode

Our LinearGaugeCustomPainter extends CustomPainter which gives us access to the paint and shouldRepaint methods.

We will use our paint method to create the components mentioned above.

Drawing the main axis

Before we draw the main axis we first have to determine where it will begin and end. the size parameter contains the height and width of the canvas. We must draw within the limits of the width and height parameters or our drawing won't be visible on the screen.

Let's define the start point and end point of our main axis.

class LinearGaugeCustomPainter extends CustomPainter {
  ///find Main Axis start point
  Offset getMainAxisStartPoint(Size size) => Offset(size.width / 2, size.height / 7);

  ///find Main Axis endpoint
  Offset getMainAxisEndPoint(Size size) => Offset(size.width / 2, size.height / 1.2);
...
}
Enter fullscreen mode Exit fullscreen mode

To draw the main axis we need to draw a line from a start point of our choosing to an endpoint of our choosing. We determine these point using the Offset class. This class accepts a x-axis value and a y-axis value.

To place the main axis of the gauge in the middle of the canvas along the x-axis we divide the size.width by 2. We then set the y-axis to the lowest and highest point of the main axis by dividing the height of the canvas by a constant.

The the constants 7 and 1.2 was chosen because those are the height position at with I want the main axis to start and end. Feel free to play around with the constants to determine your prefered starting and endpoints. The size parameter is used to ensure the main axis scale in proportion to the height of the canvas on any device.

class LinearGaugeCustomPainter extends CustomPainter {
  ...
  /// Draws the main axis of the Gauge
  void drawGaugeMainAxis(Canvas canvas, Size size) {
    final gaugeMainAxisPainter = Paint()
      ..color = Colors.grey.shade300
      ..strokeWidth = 5.0;
    canvas.drawLine(getMainAxisStartPoint(size), getMainAxisEndPoint(size), gaugeMainAxisPainter);
  }
  ...
}
Enter fullscreen mode Exit fullscreen mode

To draw the main axis we call the canvas.drawLine() method and pass in the start point offset value and endpoint offset value. It also expects a Paint() class that describes the style to use when drawing on the canvas.

class LinearGaugeCustomPainter extends CustomPainter {
  ...

  @override
  void paint(Canvas canvas, Size size) {
    drawGaugeMainAxis(canvas, size);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}
Enter fullscreen mode Exit fullscreen mode

We call our drawGaugeMainAxis() method in inside the paint method since this method is called whenever the object needs to paint.

We return true to our shouldRepaint() since we'll be adding animation to our gauge and we'll need to repaint during the animation from 0 to the actual value.

Run the code and our scale widget will look like;

main axis

Conclusions

We've created the main axis of our linear gauge and in the process learnt how to draw a line on the canvas at a start and endpoint of our choosing. In the next article in this series we'll learn how to position our major ticks along the main axis.

Top comments (0)

Let's Get Hacking

Join the DEV x Linode Hackathon 2022 and use your ingenuity and creativity to build using Linode.

β†’ Join the Hackathon <-