Introduction
The gauge_indicator
package allows you to create gauge indicators, which are graphical representations of a value within a range. This guide will show you how to integrate and use this package to create gauge indicators in your Flutter app.
Content
1.Add the gauge_indicator
dependency:
Open your pubspec.yaml
file and add the gauge_indicator
dependency.
dependencies:
gauge_indicator: ^latest_version
Run flutter pub get
to install the package.
2.Import the package:
Import the gauge_indicator
package in your Dart file.
import 'package:gauge_indicator/gauge_indicator.dart';
3.Create a gauge indicator:
Use the GaugeIndicator
widget to create a gauge indicator.
GaugeIndicator(
value: 0.5,
minValue: 0,
maxValue: 1,
gaugeColor: Colors.grey,
indicatorColor: Colors.blue,
labelText: 'Progress',
)
Customize the value
, minValue
, maxValue
, gaugeColor
, indicatorColor
, and labelText
parameters as needed. The value
parameter represents the value to be displayed on the gauge indicator, and the minValue
and maxValue
parameters define the range of the gauge. The gaugeColor
parameter sets the color of the gauge, while the indicatorColor
parameter sets the color of the indicator. The labelText
parameter sets the text label to be displayed below the gauge.
4.Run the app:
Run your Flutter app to see the gauge indicator. It should display the value within the specified range with the gauge and indicator colors as set.
Sample Code
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
import 'package:gauge_indicator/gauge_indicator.dart';
class GaugeIndicatorWidget extends StatelessWidget {
const GaugeIndicatorWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 1,
centerTitle: true,
title: Text(
"Gauge indicator",
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w700, fontSize: 22),
),
backgroundColor: Color.fromARGB(255, 27, 255, 255),
),
body: Center(
child: AnimatedRadialGauge(
duration: const Duration(seconds: 1),
curve: Curves.elasticOut,
radius: 130,
value: 32,
axis: const GaugeAxis(
min: 10,
max: 120,
degrees: 230,
style: GaugeAxisStyle(
thickness: 40,
background: Color(0xFFDFE2EC),
segmentSpacing: 24,
),
pointer: GaugePointer.needle(
color: Colors.black,
height: 83,
width: 23,
borderRadius: 20,
),
progressBar: GaugeProgressBar.rounded(
color: Color.fromARGB(255, 50, 80, 197),
),
segments: [
GaugeSegment(
from: 33,
to: 33.3,
color: Color(0xFFD9DEEB),
cornerRadius: Radius.zero,
),
GaugeSegment(
from: 33.3,
to: 66.6,
color: Color(0xFFD9DEEB),
cornerRadius: Radius.zero,
),
GaugeSegment(
from: 66.6,
to: 100,
color: Color(0xFFD9DEEB),
cornerRadius: Radius.zero,
),
],
),
),
),
);
}
}
Output
Sample Code – 2
import 'package:flutter/material.dart';
import 'package:flutter_one/views/gauge_indicator/gauge_indicator.dart';
import 'package:gauge_indicator/gauge_indicator.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'dart:math' as math show Random;
import 'dart:math' as math;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Radial gauge',
theme: ThemeData(
primarySwatch: Colors.blue,
tabBarTheme: const TabBarTheme(
labelColor: Colors.black,
),
),
home: const Scaffold(
body: RadialGaugeExamplePage(),
),
);
}
}
class RadialGaugeExamplePage extends StatefulWidget {
const RadialGaugeExamplePage({Key? key}) : super(key: key);
@override
State<RadialGaugeExamplePage> createState() => _RadialGaugeExamplePageState();
}
class _RadialGaugeExamplePageState extends State<RadialGaugeExamplePage> {
final _controller = GaugeDataController();
@override
Widget build(BuildContext context) {
final viewSize = MediaQuery.sizeOf(context);
final isMobile = viewSize.width < 700;
return Scaffold(
body: Builder(builder: (context) {
final gaugeWidget = Center(
child: AnimatedBuilder(
animation: _controller,
builder: (context, _) => Container(
decoration: BoxDecoration(
border: Border.all(
color: const Color(0xFFEFEFEF),
),
),
width: _controller.parentWidth,
height: _controller.parentHeight,
child: AnimatedRadialGauge(
radius: _controller.gaugeRadius,
builder: _controller.hasPointer && _controller.pointerType == PointerType.needle
? null
: (context, _, value) => RadialGaugeLabel(
style: TextStyle(
color: const Color(0xFF002E5F),
fontSize: _controller.fontSize,
fontWeight: FontWeight.bold,
),
value: value,
),
duration: const Duration(milliseconds: 2000),
curve: Curves.elasticOut,
value: _controller.value,
axis: GaugeAxis(
min: 0,
max: 100,
degrees: _controller.degree,
pointer: _controller.hasPointer ? _controller.getPointer(_controller.pointerType) : null,
progressBar: _controller.hasProgressBar ? _controller.getProgressBar(_controller.progressBarType) : null,
transformer: const GaugeAxisTransformer.colorFadeIn(
interval: Interval(0.0, 0.3),
background: Color(0xFFD9DEEB),
),
style: GaugeAxisStyle(
thickness: _controller.thickness,
background: _controller.backgroundColor,
segmentSpacing: _controller.spacing,
blendColors: false,
cornerRadius: Radius.circular(_controller.segmentsRadius),
),
segments: _controller.segments.map((e) => e.copyWith(cornerRadius: Radius.circular(_controller.segmentsRadius))).toList(),
),
),
),
),
);
if (isMobile) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
const PageTitle(title: 'gauge_indicator', isSmall: true),
Expanded(
child: gaugeWidget,
),
SizedBox(
height: math.min(viewSize.height * 0.6, 400),
child: DecoratedBox(
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor,
border: const Border(top: BorderSide(color: Color(0xFFDDDDDD))),
),
child: GaugeConfigPanel(controller: _controller),
),
),
],
);
} else {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
decoration: const BoxDecoration(
border: Border(right: BorderSide(color: Color(0xFFDDDDDD))),
),
width: 350,
child: Column(
children: [
const PageTitle(title: 'gauge_indicator'),
Expanded(
child: GaugeConfigPanel(controller: _controller),
),
],
),
),
Expanded(child: gaugeWidget),
],
);
}
}),
);
}
}
class GaugeConfigPanel extends StatelessWidget {
final GaugeDataController _controller;
const GaugeConfigPanel({
Key? key,
required GaugeDataController controller,
}) : _controller = controller,
super(key: key);
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, _) => ListView(
padding: const EdgeInsets.symmetric(vertical: 24),
children: [
ValueSlider(
label: "Value",
min: 0,
max: 100,
value: _controller.sliderValue,
onChanged: (val) {
_controller.sliderValue = double.parse(val.toStringAsFixed(2));
},
onChangeEnd: (newVal) {
_controller.value = newVal;
},
),
ValueSlider(
label: "Degrees",
min: 30,
max: 360,
value: _controller.degree,
onChanged: (val) {
_controller.degree = double.parse(val.toStringAsFixed(2));
},
),
ValueSlider(
label: "Segments radius",
min: 0,
max: 20,
value: _controller.segmentsRadius,
onChanged: (val) {
_controller.segmentsRadius = double.parse(val.toStringAsFixed(2));
},
),
ValueSlider(
label: "Thickness",
min: 5,
max: 40,
value: _controller.thickness,
onChanged: (val) {
_controller.thickness = double.parse(val.toStringAsFixed(2));
},
),
ValueSlider(
label: "Spacing",
min: 0,
max: 20,
value: _controller.spacing,
onChanged: (val) {
_controller.spacing = double.parse(val.toStringAsFixed(2));
},
),
ValueSlider(
label: "Font size",
min: 8,
max: 48,
value: _controller.fontSize,
onChanged: (val) {
_controller.fontSize = double.parse(val.toStringAsFixed(2));
},
),
ValueSlider(
label: "Gauge radius",
min: 50,
max: 250,
value: _controller.gaugeRadius,
onChanged: (val) {
_controller.gaugeRadius = double.parse(val.toStringAsFixed(2));
},
),
ValueSlider(
label: "Parent height",
min: 150,
max: 500,
value: _controller.parentHeight,
onChanged: (val) {
_controller.parentHeight = double.parse(val.toStringAsFixed(2));
},
),
ValueSlider(
label: "Parent width",
min: 150,
max: 500,
value: _controller.parentWidth,
onChanged: (val) {
_controller.parentWidth = double.parse(val.toStringAsFixed(2));
},
),
const Divider(),
ColorField(
title: "Background color",
color: _controller.backgroundColor,
onColorChanged: (c) => _controller.backgroundColor = c,
),
ColorField(
title: "Segment 1 color",
color: _controller.segments[0].color,
onColorChanged: (c) => _controller.setSegmentColor(0, c),
),
ColorField(
title: "Segment 2 color",
color: _controller.segments[1].color,
onColorChanged: (c) => _controller.setSegmentColor(1, c),
),
ColorField(
title: "Segment 3 color",
color: _controller.segments[2].color,
onColorChanged: (c) => _controller.setSegmentColor(2, c),
),
const Divider(),
CheckboxListTile(
title: const Text("Has progress bar"),
value: _controller.hasProgressBar,
onChanged: (selected) {
if (selected != null) {
_controller.hasProgressBar = selected;
}
}),
if (_controller.hasProgressBar)
Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
child: DropdownButton<GaugeProgressPlacement>(
items: [
for (final val in GaugeProgressPlacement.values)
DropdownMenuItem(
child: Text("Placement: ${val.name}"),
value: val,
)
],
value: _controller.progressBarPlacement,
onChanged: (val) {
if (val == null) return;
_controller.progressBarPlacement = val;
},
),
),
if (_controller.hasProgressBar)
Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
child: DropdownButton<ProgressBarType>(
items: [
for (final val in ProgressBarType.values)
DropdownMenuItem(
child: Text("Type: ${val.name}"),
value: val,
)
],
value: _controller.progressBarType,
onChanged: (val) {
if (val == null) return;
_controller.progressBarType = val;
},
),
),
if (_controller.hasProgressBar)
ColorField(
title: "Select progress bar color",
color: _controller.progressBarColor,
onColorChanged: (c) => _controller.progressBarColor = c,
),
const Divider(),
CheckboxListTile(
title: const Text("Has pointer"),
value: _controller.hasPointer,
onChanged: (selected) async {
if (selected != null) {
_controller.hasPointer = selected;
}
}),
if (_controller.hasPointer)
Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
child: DropdownButton<PointerType>(
items: [
for (final val in PointerType.values)
DropdownMenuItem(
child: Text("Type: ${val.name}"),
value: val,
)
],
value: _controller.pointerType,
onChanged: (val) {
if (val == null) return;
_controller.pointerType = val;
},
),
),
if (_controller.hasPointer)
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: ValueSlider(
label: "Pointer size",
min: 16,
max: 36,
value: _controller.pointerSize,
onChanged: (val) {
_controller.pointerSize = val;
},
),
),
if (_controller.hasPointer)
ColorField(
title: "Pointer color",
color: _controller.pointerColor,
onColorChanged: (c) => _controller.pointerColor = c,
),
const Divider(),
Center(
child: ElevatedButton(
onPressed: _controller.randomizeSegments,
child: const Text("Randomize segments"),
),
),
],
),
);
}
}
Future<Color?> pickColor(BuildContext context, Color initialColor) {
Color color = initialColor;
return showDialog<Color>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Pick a color'),
content: SingleChildScrollView(
child: ColorPicker(
pickerColor: color,
onColorChanged: (c) => color = c,
),
),
actions: <Widget>[
ElevatedButton(
child: const Text('Select'),
onPressed: () {
Navigator.of(context).pop(color);
},
),
],
),
);
}
class ColorField extends StatelessWidget {
final String title;
final Color color;
final ValueChanged<Color> onColorChanged;
const ColorField({
Key? key,
required this.title,
required this.color,
required this.onColorChanged,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(title),
onTap: () => pickColor(
context,
color,
).then((color) {
if (color != null) {
onColorChanged(color);
}
}),
trailing: Container(
width: 40,
height: 40,
color: color,
),
);
}
}
class PageTitle extends StatelessWidget {
final String title;
final bool isSmall;
const PageTitle({
Key? key,
required this.title,
this.isSmall = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
width: double.infinity,
padding: isSmall ? const EdgeInsets.all(4) : const EdgeInsets.all(16),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: Color(0xFFDDDDDD),
),
)),
child: Text(
title,
style: TextStyle(
fontSize: isSmall ? 14 : 24,
),
),
);
}
}
class ValueSlider extends StatelessWidget {
final String label;
final double value;
final ValueChanged<double> onChanged;
final ValueChanged<double>? onChangeEnd;
final double min;
final double max;
const ValueSlider({
Key? key,
required this.label,
required this.onChanged,
this.onChangeEnd,
required this.value,
required this.min,
required this.max,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Text(
"$label: ${value.toStringAsFixed(2)}",
style: const TextStyle(
fontSize: 16,
),
),
),
Slider(
min: min,
max: max,
value: value,
onChanged: onChanged,
onChangeEnd: onChangeEnd,
),
],
);
}
}
enum PointerType { needle, triangle, circle }
enum ProgressBarType { rounded, basic }
const colors = [
Colors.green,
Color(0xFF34C759),
Colors.amber,
Colors.red,
Colors.blue,
Colors.blueAccent,
Colors.lightBlue,
Colors.grey,
Colors.black,
Color(0xFFD9DEEB),
];
class GaugeDataController extends ChangeNotifier {
double _value = 65;
double get value => _value;
set value(double val) {
if (val != value) {
_value = val;
notifyListeners();
}
}
double _sliderValue = 65;
double get sliderValue => _sliderValue;
set sliderValue(double value) {
if (sliderValue != value) {
_sliderValue = value;
notifyListeners();
}
}
double _degree = 260;
double get degree => _degree;
set degree(double value) {
if (degree != value) {
_degree = value;
notifyListeners();
}
}
bool _hasPointer = true;
bool get hasPointer => _hasPointer;
set hasPointer(bool value) {
if (value != hasPointer) {
_hasPointer = value;
notifyListeners();
}
}
bool _hasProgressBar = true;
bool get hasProgressBar => _hasProgressBar;
set hasProgressBar(bool value) {
if (value != hasProgressBar) {
_hasProgressBar = value;
notifyListeners();
}
}
double _segmentsRadius = 8;
double get segmentsRadius => _segmentsRadius;
set segmentsRadius(double value) {
if (value != segmentsRadius) {
_segmentsRadius = value;
notifyListeners();
}
}
Color _progressBarColor = Colors.purple;
Color get progressBarColor => _progressBarColor;
set progressBarColor(Color value) {
if (value != progressBarColor) {
_progressBarColor = value;
notifyListeners();
}
}
Color _backgroundColor = Colors.transparent;
Color get backgroundColor => _backgroundColor;
set backgroundColor(Color value) {
if (value != backgroundColor) {
_backgroundColor = value;
notifyListeners();
}
}
Color _pointerColor = const Color(0xFF002E5F);
Color get pointerColor => _pointerColor;
set pointerColor(Color value) {
if (value != pointerColor) {
_pointerColor = value;
notifyListeners();
}
}
double _parentWidth = 500;
double get parentWidth => _parentWidth;
set parentWidth(double value) {
if (value != parentWidth) {
_parentWidth = value;
notifyListeners();
}
}
double _parentHeight = 500;
double get parentHeight => _parentHeight;
set parentHeight(double value) {
if (value != parentHeight) {
_parentHeight = value;
notifyListeners();
}
}
double _gaugeRadius = 150;
double get gaugeRadius => _gaugeRadius;
set gaugeRadius(double value) {
if (value != gaugeRadius) {
_gaugeRadius = value;
notifyListeners();
}
}
double _thickness = 35;
double get thickness => _thickness;
set thickness(double value) {
if (value != thickness) {
_thickness = value;
notifyListeners();
}
}
double _spacing = 8;
double get spacing => _spacing;
set spacing(double value) {
if (value != spacing) {
_spacing = value;
notifyListeners();
}
}
double _fontSize = 46;
double get fontSize => _fontSize;
set fontSize(double value) {
if (value != fontSize) {
_fontSize = value;
notifyListeners();
}
}
double _pointerSize = 26;
double get pointerSize => _pointerSize;
set pointerSize(double value) {
if (value != pointerSize) {
_pointerSize = value;
notifyListeners();
}
}
PointerType _pointerType = PointerType.needle;
PointerType get pointerType => _pointerType;
set pointerType(PointerType value) {
if (value != pointerType) {
_pointerType = value;
notifyListeners();
}
}
GaugeProgressPlacement _progressBarPlacement = GaugeProgressPlacement.inside;
GaugeProgressPlacement get progressBarPlacement => _progressBarPlacement;
set progressBarPlacement(GaugeProgressPlacement value) {
if (value != progressBarPlacement) {
_progressBarPlacement = value;
notifyListeners();
}
}
ProgressBarType _progressBarType = ProgressBarType.basic;
ProgressBarType get progressBarType => _progressBarType;
set progressBarType(ProgressBarType value) {
if (value != progressBarType) {
_progressBarType = value;
notifyListeners();
}
}
GaugePointer getPointer(PointerType pointerType) {
switch (pointerType) {
case PointerType.needle:
return GaugePointer.needle(
width: pointerSize * 0.625,
height: pointerSize * 4,
color: pointerColor,
position: GaugePointerPosition.center(
offset: Offset(0, pointerSize * 0.3125),
),
);
case PointerType.triangle:
return GaugePointer.triangle(
width: pointerSize,
height: pointerSize,
borderRadius: pointerSize * 0.125,
color: pointerColor,
position: GaugePointerPosition.surface(
offset: Offset(0, thickness * 0.6),
),
border: GaugePointerBorder(
color: Colors.white,
width: pointerSize * 0.125,
),
);
case PointerType.circle:
return GaugePointer.circle(
radius: pointerSize * 0.5,
color: pointerColor,
border: GaugePointerBorder(
color: Colors.white,
width: pointerSize * 0.125,
),
);
}
}
List<GaugeSegment> get segments => _segments;
set segments(List<GaugeSegment> value) {
if (value != segments) {
_segments = value;
notifyListeners();
}
}
List<GaugeSegment> _segments = <GaugeSegment>[
const GaugeSegment(
from: 0,
to: 60.0,
color: Color(0xFFD9DEEB),
cornerRadius: Radius.zero,
),
const GaugeSegment(
from: 60.0,
to: 85.0,
color: Color(0xFFD9DEEB),
cornerRadius: Radius.zero,
),
const GaugeSegment(
from: 85.0,
to: 100,
color: Color(0xFFD9DEEB),
cornerRadius: Radius.zero,
),
];
void randomizeSegments() {
final random = math.Random();
final a = random.nextDouble() * 100;
final b = random.nextDouble() * 100;
final stops = a > b ? [b, a] : [a, b];
segments = <GaugeSegment>[
GaugeSegment(
from: 0,
to: stops[0],
color: colors[random.nextInt(colors.length)],
cornerRadius: Radius.zero,
),
GaugeSegment(
from: stops[0],
to: stops[1],
color: colors[random.nextInt(colors.length)],
cornerRadius: Radius.zero,
),
GaugeSegment(
from: stops[1],
to: 100,
color: colors[random.nextInt(colors.length)],
cornerRadius: Radius.zero,
),
];
}
GaugeProgressBar getProgressBar(ProgressBarType progressBarType) {
switch (progressBarType) {
case ProgressBarType.rounded:
return GaugeProgressBar.rounded(
color: progressBarColor,
placement: progressBarPlacement,
);
case ProgressBarType.basic:
return GaugeProgressBar.basic(
color: progressBarColor,
placement: progressBarPlacement,
);
}
}
void setSegmentColor(int index, Color color) {
RangeError.checkValidIndex(index, segments);
segments[index] = segments[index].copyWith(
color: color,
);
notifyListeners();
}
}
Output-2
Conclusion
By following these steps, you can easily integrate the gauge_indicator
package into your Flutter app and create gauge indicators. This can be useful for displaying progress, levels, or any other value within a specified range in your app.