Copied RSS Feed

Flutter

How to Design a Speedometer Using Flutter Radial Gauge

In this blog you will get a quick overview of our Flutter Radial Gauge and its features by designing a speedometer mobile application.

The Radial Gauge for Flutter is a data visualization widget written in Dart that displays numerical values on a circular scale. It has a rich set of features such as axes, ranges, pointers, and annotations that are fully customizable and extendable. You can use this to design mobile applications that include a speedometer, temperature monitor, dashboard, multi-axis clock, watch, compass, and so on.

To design a speedometer, you need the following features in a radial gauge widget:

  • Axes: Define the speedometer scale values in numbers from start to end with tick marks.
  • Ranges: Indicate the speedometer color ranges as a gradient.
  • Pointers: Indicate the current speedometer value on the range.
  • Pointer animation: Animate the pointer in a visually appealing way when the pointer moves from one value to another.
  • Annotations: Display the current speedometer value.

This section explains how to design a speedometer with a directional compass that indicates the current direction by customizing the appearance of the radial gauge. The fully developed application will appear as shown in the following screenshot.

Completed speedometer application

Note: Dark theme mode is used for this demo app.

Configuring the Radial Gauge widget in the Flutter project

Create a simple project using the instructions given in the Get Started documentation on the Flutter website.

Add dependency

Add the Syncfusion Flutter Gauge dependency to your pubspec.yaml file.

dependencies: syncfusion_flutter_gauges: ^18.2.44

Get packages

Run the following command to get the required packages.

$ flutter pub get

Import package

Import the following package in your Dart code.

import 'package:syncfusion_flutter_gauges/gauges.dart';

After the package has been imported, initialize the SfRadialGauge as a child of any widget, such as a container widget.

Add speedometer scale range

The first step in designing a speedometer is to add speed scale values as numbers from the minimum, 0, to the maximum, 200, with a specific interval. This can be achieved using the axes in the radial gauge.

Axes contain a collection of axis elements, and you can add any number of radial axes inside the gauge. In the Radial Gauge, you can display the speedometer labels from 0 to 200 using the minimum and maximum properties and customize their style using the axisLabelStyle property.

Axes have two types of tick marks: major and minor. Major ticks have labels and are used to specify the primary value intervals. Minor ticks do not have labels and are used to define the secondary value interval. You can specify the ticks’ appearance and position-related properties using the majorTickStyle and minorTickStyle properties for the axis.

SfRadialGauge(
    axes: <RadialAxis>[
      RadialAxis(minimum: 0, maximum: 200, labelOffset: 30,
          axisLineStyle: AxisLineStyle(
          thicknessUnit: GaugeSizeUnit.factor,thickness: 0.03),
          majorTickStyle: MajorTickStyle(length: 6,thickness: 4,color: Colors.white),
          minorTickStyle: MinorTickStyle(length: 3,thickness: 3,color: Colors.white),
          axisLabelStyle: GaugeTextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 14 )
      )
    ]
)
Major and minor ticks in the gauge

Add speed limit alert

Next, we’ll add speed alerts in the form of color indicators of how fast a person is traveling. The green end of the color range will indicate a safe speed, the yellow color range will indicate a precarious speed, and the red color range will indicate a dangerous, high speed. To achieve this, we’ll use the range support in the Radial Gauge widget.

A range is a visual element that helps you visualize where a value falls on a radial scale. You can set color indicators as either a single range with a gradient or multiple ranges. In this blog, we’ll use a range with a gradient that contains three colors.

Every range has start and end values, and these can be specified using the startValue and endValue properties. The width of a range can be customized using the startWidth and endWidth properties.

ranges: <GaugeRange>[
  GaugeRange(startValue: 0, endValue: 200, sizeUnit: GaugeSizeUnit.factor,startWidth: 0.03,endWidth: 0.03,
      gradient: SweepGradient(
          colors: const<Color>[Colors.green,Colors.yellow,Colors.red],
          stops: const<double>[0.0,0.5,1]))],
Color gradient range

Add needle pointer

Next, we need to add a needle pointer to indicate the speed in the speedometer. This can be achieved using the pointer support in the Radial Gauge.

A needle pointer will be used to design the value indication symbol and point out the current value. Add the needle pointer in the Pointers collection and customize its length, size, and knob style.

pointers: <GaugePointer>[NeedlePointer(value:_value, needleLength: 0.95, enableAnimation: true,
    animationType: AnimationType.ease, needleStartWidth: 1.5, needleEndWidth: 6, needleColor: Colors.red,
    knobStyle: KnobStyle(knobRadius: 0.09))],
Needle pointer in the speedometer

Display current speed value

Finally, we need to display the current speed value at the bottom of the speedometer. This can be achieved using the annotation support in the Radial Gauge.

Using annotations, you can add text widgets over the gauge to display the current pointer value and measurement info. The position of annotations can be customized using the angle and positionFactor properties.

annotations: <GaugeAnnotation>[
  GaugeAnnotation(widget: Container(child:
  Column(
    children: <Widget>[
      Text(_value.toString(), style: TextStyle(fontSize: 25,fontWeight: FontWeight.bold)),
      SizedBox(height: 20),
      Text('mph', style: TextStyle(fontSize: 14,fontWeight: FontWeight.bold))]
  )), angle: 90, positionFactor: 0.75)]
Speedometer with annotation to display speed value

Add directional compass inside the speedometer

Additionally, you can add a directional compass to the speedometer to show the current direction of travel. This will increase the functionality of the speedometer app. To implement a compass, we will add another axis inside the Radial Gauge widget using the Axes property. This axis will be included behind the main axis at the 0 index in the axes collection so that the needle pointer will be displayed on top as shown in the following figure.

axes: <RadialAxis>[
  RadialAxis(startAngle: 270, endAngle: 270,minimum: 0,maximum: 80,interval: 10,radiusFactor: 0.4,
      showAxisLine: false, showLastLabel: false, minorTicksPerInterval: 4,
      majorTickStyle: MajorTickStyle(length: 8,thickness: 3,color: Colors.white),
      minorTickStyle: MinorTickStyle(length: 3,thickness: 1.5,color: Colors.grey),
      axisLabelStyle: GaugeTextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 14 ),
      onLabelCreated: labelCreated),
  RadialAxis()]
Compass added to speedometer

In the previous figure, the axis labels are displayed from 0 to 80 with an interval of 20. In the directional compass, we need to define string labels that denote corresponding directions. So, we will customize the numeric axis labels using the onLabelCreated event in the axis to note the north, east, south, and west directions.

axes: <RadialAxis>[
  RadialAxis(startAngle: 270, endAngle: 270,minimum: 0,maximum: 80,interval: 10,radiusFactor: 0.4,
      onLabelCreated: labelCreated),
  RadialAxis()]
void labelCreated(AxisLabelCreatedArgs args) {
  if(args.text =='0') {
    args.text = 'N';
    args.labelStyle=GaugeTextStyle(color: Colors.red,fontWeight: FontWeight.bold,fontSize: 14);
  }
  else if(args.text=='10')
    args.text='';
  else if(args.text=='20')
    args.text='E';
  else if(args.text=='30')
    args.text='';
  else if(args.text=='40')
    args.text='S';
  else if(args.text=='50')
    args.text='';
  else if(args.text=='60')
    args.text='W';
  else if(args.text=='70')
    args.text='';
}
Compass with cardinal directions

Animate pointer with real-time data

In a real-time speedometer app, data may be fetched from a data service or device GPS to update the pointer value. For this demo, data will be updated using a timer with a 1-second duration, and the app state will be changed to rebuild the widgets. The _value double variable is used to set the pointer value and the annotation’s text value. In each time tick, the _value variable is assigned with some random value in the setState callback as shown in the following code to update the pointer and annotation text value.

_timer = Timer.periodic(const Duration(milliseconds: 1000),(_timer)
{
  setState(() {
    _value = (Random().nextDouble() * 40) + 60;
  });
});

You can download the complete sample code from this GitHub location.

Conclusion

The Syncfusion Radial Gauge widget for Flutter has been designed with flexible UI customization options to make adapting your app easy. It includes developer-friendly APIs to increase productivity.

Feel free to browse the Radial Gauge documentation to learn more about its features and APIs. You can also see Syncfusion’s Flutter app with many examples in this GitHub repo. Don’t miss our demo app in Google Play and the App Store.

Also, if you need a new widget for the Flutter framework that we don’t offer currently, please let us know in the comments section below. You can also contact us through our support forumDirect-Trac, or feedback portal. As always, we are happy to assist you!

Meet the Author

Sheik Syed

Sheik Syed Abthaheer is a Product Manager at Syncfusion. He has been a .NET developer since 2012, working on the custom control development for Microsoft technologies.