LinearProgressIndicator class

A Material Design linear progress indicator, also known as a progress bar.

Learn more about LinearProgressIndicator on the Flutter YouTube channel.

A widget that shows progress along a line. There are two kinds of linear progress indicators:

  • Determinate. Determinate progress indicators have a specific value at each point in time, and the value should increase monotonically from 0.0 to 1.0, at which time the indicator is complete. To create a determinate progress indicator, use a non-null value between 0.0 and 1.0.
  • Indeterminate. Indeterminate progress indicators do not have a specific value at each point in time and instead indicate that progress is being made without indicating how much progress remains. To create an indeterminate progress indicator, use a null value.

The indicator line is displayed with valueColor, an animated value. To specify a constant color value use: AlwaysStoppedAnimation<Color>(color).

The minimum height of the indicator can be specified using minHeight. The indicator can be made taller by wrapping the widget with a SizedBox.

This example showcases determinate and indeterminate LinearProgressIndicators. The LinearProgressIndicators will use the updated Material 3 Design appearance when setting the LinearProgressIndicator.year2023 flag to false.

To see it in action, copy and run this code snippet on DartPad.

import 'package:material_ui/material_ui.dart';

/// Flutter code sample for [LinearProgressIndicator].

void main() => runApp(const ProgressIndicatorExampleApp());

class ProgressIndicatorExampleApp extends StatelessWidget {
  const ProgressIndicatorExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: ProgressIndicatorExample());
  }
}

class ProgressIndicatorExample extends StatefulWidget {
  const ProgressIndicatorExample({super.key});

  @override
  State<ProgressIndicatorExample> createState() =>
      _ProgressIndicatorExampleState();
}

class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample>
    with TickerProviderStateMixin {
  late AnimationController controller;
  bool year2023 = true;

  @override
  void initState() {
    super.initState();
    controller =
        AnimationController(
            /// [AnimationController]s can be created with `vsync: this` because of
            /// [TickerProviderStateMixin].
            vsync: this,
            duration: const Duration(seconds: 5),
          )
          ..addListener(() {
            setState(() {});
          })
          ..repeat(reverse: true);
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        spacing: 16.0,
        mainAxisAlignment: .center,
        children: <Widget>[
          const Text('Determinate LinearProgressIndicator'),
          Padding(
            padding: const .symmetric(horizontal: 16),
            child: LinearProgressIndicator(
              // ignore: deprecated_member_use
              year2023: year2023,
              value: controller.value,
            ),
          ),
          const Text('Indeterminate LinearProgressIndicator'),
          Padding(
            padding: const .symmetric(horizontal: 16),
            // ignore: deprecated_member_use
            child: LinearProgressIndicator(year2023: year2023),
          ),
          SwitchListTile(
            value: year2023,
            title: year2023
                ? const Text('Switch to latest M3 style')
                : const Text('Switch to year2023 M3 style'),
            onChanged: (bool value) {
              setState(() {
                year2023 = !year2023;
              });
            },
          ),
        ],
      ),
    );
  }
}

This sample shows the creation of a LinearProgressIndicator with a changing value. When toggling the switch, LinearProgressIndicator uses a determinate value. As described in: https://m3.material.io/components/progress-indicators/overview

To see it in action, copy and run this code snippet on DartPad.

import 'package:material_ui/material_ui.dart';

/// Flutter code sample for [LinearProgressIndicator].

void main() => runApp(const ProgressIndicatorExampleApp());

class ProgressIndicatorExampleApp extends StatelessWidget {
  const ProgressIndicatorExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: ProgressIndicatorExample());
  }
}

class ProgressIndicatorExample extends StatefulWidget {
  const ProgressIndicatorExample({super.key});

  @override
  State<ProgressIndicatorExample> createState() =>
      _ProgressIndicatorExampleState();
}

class _ProgressIndicatorExampleState extends State<ProgressIndicatorExample>
    with TickerProviderStateMixin {
  late AnimationController controller;
  bool determinate = false;

  @override
  void initState() {
    super.initState();
    controller =
        AnimationController(
            /// [AnimationController]s can be created with `vsync: this` because of
            /// [TickerProviderStateMixin].
            vsync: this,
            duration: const Duration(seconds: 2),
          )
          ..addListener(() {
            setState(() {});
          })
          ..repeat(reverse: true);
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const .all(20.0),
        child: Column(
          spacing: 16.0,
          mainAxisAlignment: .center,
          children: <Widget>[
            const Text(
              'Linear progress indicator',
              style: TextStyle(fontSize: 20),
            ),
            LinearProgressIndicator(
              value: determinate ? controller.value : null,
              semanticsLabel: 'Linear progress indicator',
            ),
            Row(
              children: <Widget>[
                Expanded(
                  child: Text(
                    '${determinate ? 'Determinate' : 'Indeterminate'} Mode',
                    style: Theme.of(context).textTheme.titleSmall,
                  ),
                ),
                Switch(
                  value: determinate,
                  onChanged: (bool value) {
                    setState(() {
                      determinate = value;
                      if (determinate) {
                        controller.stop();
                      } else {
                        controller
                          ..forward(from: controller.value)
                          ..repeat();
                      }
                    });
                  },
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Animation synchronization

When multiple CircularProgressIndicators or LinearProgressIndicators are animating on screen simultaneously (e.g., in a list of loading items), their uncoordinated animations can appear visually cluttered. To address this, the animation of an indicator can be driven by a custom AnimationController.

This allows multiple indicators to be synchronized to a single animation source. The most convenient way to achieve this for a group of indicators is by providing a controller via ProgressIndicatorTheme (see ProgressIndicatorThemeData.controller). All CircularProgressIndicators or LinearProgressIndicators within that theme's subtree will then share the same animation, resulting in a more coordinated and visually pleasing effect.

Alternatively, a specific AnimationController can be passed directly to the controller property of an individual indicator.

See the documentation of CircularProgressIndicator for an example on this topic.

See also:

Inheritance

Constructors

LinearProgressIndicator({Key? key, double? value, Color? backgroundColor, Color? color, Animation<Color?>? valueColor, double? minHeight, String? semanticsLabel, String? semanticsValue, BorderRadiusGeometry? borderRadius, Color? stopIndicatorColor, double? stopIndicatorRadius, double? trackGap, @Deprecated('Set this flag to false to opt into the 2024 progress indicator appearance. Defaults to true. ' 'In the future, this flag will default to false. Use ProgressIndicatorThemeData to customize individual properties. ' 'This feature was deprecated after v3.26.0-0.1.pre.') bool? year2023, AnimationController? controller})
Creates a linear progress indicator.
const

Properties

backgroundColor → Color?
Color of the track being filled by the linear indicator.
no setteroverride
borderRadius → BorderRadiusGeometry?
The border radius of both the indicator and the track.
final
color → Color?
The progress indicator's color.
finalinherited
controller → AnimationController?
An optional AnimationController that controls the animation of this indeterminate progress indicator.
final
hashCode → int
The hash code for this object.
no setterinherited
key → Key?
Controls how one widget replaces another widget in the tree.
finalinherited
minHeight → double?
The minimum height of the line used to draw the linear indicator.
final
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
semanticsLabel → String?
The SemanticsProperties.label for this progress indicator.
finalinherited
semanticsValue → String?
The SemanticsProperties.value for this progress indicator.
finalinherited
stopIndicatorColor → Color?
The color of the stop indicator.
final
stopIndicatorRadius → double?
The radius of the stop indicator.
final
trackGap → double?
The gap between the indicator and the track.
final
value → double?
If non-null, the value of this progress indicator.
finalinherited
valueColor → Animation<Color?>?
The progress indicator's color as an animated value.
finalinherited
year2023 → bool?
When true, the LinearProgressIndicator will use the 2023 Material Design 3 appearance.
final

Methods

createElement() → StatefulElement
Creates a StatefulElement to manage this widget's location in the tree.
inherited
createState() → State<LinearProgressIndicator>
Creates the mutable state for this widget at a given location in the tree.
override
debugDescribeChildren() → List<DiagnosticsNode>
Returns a list of DiagnosticsNode objects describing this node's children.
inherited
debugFillProperties(DiagnosticPropertiesBuilder properties) → void
Add additional properties associated with the node.
inherited
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toDiagnosticsNode({String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode
Returns a debug representation of the object that is used by debugging tools and by DiagnosticsNode.toStringDeep.
inherited
toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) → String
A string representation of this object.
inherited
toStringDeep({String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) → String
Returns a string representation of this node and its descendants.
inherited
toStringShallow({String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String
Returns a one-line detailed description of the object.
inherited
toStringShort() → String
A short, textual description of this widget.
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited

Constants

defaultAnimationDuration → const Duration
The default duration for one full cycle of the indeterminate animation.