Sequence Indicator In Flutter

Sequence Indicator In Flutter :

This flutter tutorial post is Sequence Indicator in flutter. That is used to your form fill up data more. That also known step indicator. You can customize step number indicator or step icon indicator. That is common step indicator widget in flutter.

Below the display screen shot page fill up compare true sign and change the background color.

Screenshot 1 :

Sequence Indicator In Flutter

Screenshot 2 :

Sequence Indicator In Flutter

Screenshot 3 :

Sequence Indicator In Flutter

adv_row.dart

import 'package:flutter/material.dart';

class AdvRow extends StatelessWidget {
  final EdgeInsetsGeometry padding;
  final EdgeInsetsGeometry margin;
  final Widget divider;
  final Key key;
  final MainAxisAlignment mainAxisAlignment;
  final MainAxisSize mainAxisSize;
  final CrossAxisAlignment crossAxisAlignment;
  final TextDirection textDirection;
  final VerticalDirection verticalDirection;
  final TextBaseline textBaseline;
  final List<Widget> children;

  AdvRow({
    this.padding,
    this.margin,
    this.divider,
    Key key,
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
    MainAxisSize mainAxisSize = MainAxisSize.max,
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
    TextDirection textDirection,
    VerticalDirection verticalDirection = VerticalDirection.down,
    TextBaseline textBaseline,
    List<Widget> children = const <Widget>[],
  })  : this.key = key,
        this.mainAxisAlignment = mainAxisAlignment,
        this.mainAxisSize = mainAxisSize,
        this.crossAxisAlignment = crossAxisAlignment,
        this.textDirection = textDirection,
        this.verticalDirection = verticalDirection,
        this.textBaseline = textBaseline,
        this.children = children;

  @override
  Widget build(BuildContext context) {
    List<Widget> newChildren = _rebuildChildren();

    return Container(
      padding: padding,
      margin: margin,
      child: Row(
        key: key,
        mainAxisAlignment: mainAxisAlignment,
        mainAxisSize: mainAxisSize,
        crossAxisAlignment: crossAxisAlignment,
        textDirection: textDirection,
        verticalDirection: verticalDirection,
        textBaseline: textBaseline,
        children: newChildren,
      ),
    );
  }

  List<Widget> _rebuildChildren() {
    if (children.length == 0) return [];
    List<Widget> newChildren = [];

    for (Widget child in children) {
      if (child != null) {
        newChildren.add(child);
        if (divider != null) newChildren.add(divider);
      }
    }

    if (newChildren.length > 0 && divider != null) newChildren.removeAt(newChildren.length - 1);

    return newChildren;
  }
}

class RowDivider extends StatelessWidget {
  final double size;
  final Color color;

  RowDivider(double size, {Color color})
      : this.size = size ?? 0.0,
        this.color = color ?? Colors.transparent;

  @override
  Widget build(BuildContext context) {
    return Container(width: size, height: 1.0, color: color);
  }
}

global.dart

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

const Color systemRedColor = Color(0xffE54A52);
const Color systemBlueColor = Color(0xff98dbf5);
const Color systemYellowColor = Color(0xfff3f7a6);

const Color systemGreenColor = Colors.orange;

const Color systemWhiteColor = Colors.white;
Color systemPrimaryColor = Colors.blue;
Color systemAccentColor = Colors.orange;

mini_checkbox.dart

import 'dart:math' as math;

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

class MiniCheckbox extends LeafRenderObjectWidget {
  const MiniCheckbox(
      {Key key,
        @required this.value,
        @required this.activeColor,
        @required this.inactiveColor,
        @required this.vsync,
        @required this.size});

  final bool value;
  final double size;
  final Color activeColor;
  final Color inactiveColor;
  final ValueChanged<bool> onChanged = null;
  final TickerProvider vsync;
  final BoxConstraints additionalConstraints = const BoxConstraints();

  @override
  _RenderCheckbox createRenderObject(BuildContext context) => _RenderCheckbox(
    value: value,
    checkboxSize: size,
    activeColor: activeColor,
    inactiveColor: inactiveColor,
    onChanged: onChanged,
    vsync: vsync,
    additionalConstraints: additionalConstraints,
  );

  @override
  void updateRenderObject(BuildContext context, _RenderCheckbox renderObject) {
    renderObject
      ..value = value
      ..checkboxSize = size
      ..activeColor = activeColor
      ..inactiveColor = inactiveColor
      ..onChanged = onChanged
      ..additionalConstraints = additionalConstraints
      ..vsync = vsync;
  }
}

//const double _kEdgeSize = 10.0 + 2.0;
//const Radius _kEdgeRadius = Radius.circular(10.0);
const double _kStrokeWidth = 2.0;

class _RenderCheckbox extends RenderToggleable {
  _RenderCheckbox({
    bool value,
    double checkboxSize,
    Color activeColor,
    Color inactiveColor,
    BoxConstraints additionalConstraints,
    ValueChanged<bool> onChanged,
    @required TickerProvider vsync,
  })  : _oldValue = value,
        _checkboxSize = checkboxSize ?? 0.0,
        super(
        value: value,
        tristate: false,
        activeColor: activeColor,
        inactiveColor: inactiveColor,
        onChanged: onChanged,
        additionalConstraints: additionalConstraints,
        vsync: vsync,
      );

  bool _oldValue;

  double get checkboxSize => _checkboxSize;
  double _checkboxSize;

  set checkboxSize(double newCheckboxSize) {
    if (newCheckboxSize == checkboxSize) return;
    _checkboxSize = newCheckboxSize;
  }

  @override
  set value(bool newValue) {
    if (newValue == value) return;
    _oldValue = value;
    super.value = newValue;
  }

  @override
  void describeSemanticsConfiguration(SemanticsConfiguration config) {
    super.describeSemanticsConfiguration(config);
    config.isChecked = value == true;
  }

  // The square outer bounds of the checkbox at t, with the specified origin.
  // At t == 0.0, the outer rect's size is _kEdgeSize (Checkbox.width)
  // At t == 0.5, .. is _kEdgeSize - _kStrokeWidth
  // At t == 1.0, .. is _kEdgeSize
  RRect _outerRectAt(Offset origin, double t) {
    final double inset = 1.0 - (t - 0.5).abs() * 2.0;
    final double size = (checkboxSize + _kStrokeWidth) - inset * _kStrokeWidth;
    final Rect rect =
    Rect.fromLTWH(origin.dx + inset, origin.dy + inset, size, size);
    return RRect.fromRectAndRadius(rect, Radius.circular(checkboxSize));
  }

  // The checkbox's border color if value == false, or its fill color when
  // value == true or null.
  Color _colorAt(double t) {
    // As t goes from 0.0 to 0.25, animate from the inactiveColor to activeColor.
    return (t >= 0.25
        ? activeColor
        : Color.lerp(inactiveColor, activeColor, t * 4.0));
  }

  // White stroke used to paint the check and dash.
  void _initStrokePaint(Paint paint) {
    paint
      ..color = const Color(0xFFFFFFFF)
      ..style = PaintingStyle.stroke
      ..strokeWidth = _kStrokeWidth;
  }

  void _drawBorder(Canvas canvas, RRect outer, double t, Paint paint) {
    assert(t >= 0.0 && t <= 0.5);
    final double size = outer.width;
    // As t goes from 0.0 to 1.0, gradually fill the outer RRect.
    RRect inner = outer.deflate(math.min(size / 1.0, _kStrokeWidth + size * t));
//    inner = RRect.fromRectAndRadius(inner.outerRect, Radius.circular(outer.width));
    canvas.drawDRRect(outer, inner, paint);
  }

  void _drawCheck(Canvas canvas, Offset origin, double t, Paint paint) {
    assert(t >= 0.0 && t <= 1.0);
    // As t goes from 0.0 to 1.0, animate the two check mark strokes from the
    // short side to the long side.
    final Path path = Path();
    final double size = (checkboxSize + _kStrokeWidth);
    final Offset start = Offset(size * 0.25, size * 0.55);
    final Offset mid = Offset(size * 0.4, size * 0.7);
    final Offset end = Offset(size * 0.75, size * 0.35);
    if (t < 0.5) {
      final double strokeT = t * 2.0;
      final Offset drawMid = Offset.lerp(start, mid, strokeT);
      path.moveTo(origin.dx + start.dx, origin.dy + start.dy);
      path.lineTo(origin.dx + drawMid.dx, origin.dy + drawMid.dy);
    } else {
      final double strokeT = (t - 0.5) * 2.0;
      final Offset drawEnd = Offset.lerp(mid, end, strokeT);
      path.moveTo(origin.dx + start.dx, origin.dy + start.dy);
      path.lineTo(origin.dx + mid.dx, origin.dy + mid.dy);
      path.lineTo(origin.dx + drawEnd.dx, origin.dy + drawEnd.dy);
    }
    canvas.drawPath(path, paint);
  }

  void _drawDash(Canvas canvas, Offset origin, double t, Paint paint) {
    assert(t >= 0.0 && t <= 1.0);
    // As t goes from 0.0 to 1.0, animate the horizontal line from the
    // mid point outwards.
    final double size = (checkboxSize + _kStrokeWidth);
    final Offset start = Offset(size * 0.2, size * 0.5);
    final Offset mid = Offset(size * 0.5, size * 0.5);
    final Offset end = Offset(size * 0.8, size * 0.5);
    final Offset drawStart = Offset.lerp(start, mid, 1.0 - t);
    final Offset drawEnd = Offset.lerp(mid, end, t);
    canvas.drawLine(origin + drawStart, origin + drawEnd, paint);
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    final Canvas canvas = context.canvas;
    paintRadialReaction(canvas, offset, size.center(Offset.zero));

    final Offset origin = offset +
        (size / 2.0 - Size.square((checkboxSize + _kStrokeWidth)) / 2.0);
    final AnimationStatus status = position.status;
    final double tNormalized =
    status == AnimationStatus.forward || status == AnimationStatus.completed
        ? position.value
        : 1.0 - position.value;

    // Four cases: false to null, false to true, null to false, true to false
    if (_oldValue == false || value == false) {
      final double t = value == false ? 1.0 - tNormalized : tNormalized;
      final RRect outer = _outerRectAt(origin, t);
      final Paint paint = Paint()..color = _colorAt(t);

      if (t <= 0.5) {
        final Paint innerFillPaint = Paint()
          ..color = Color.lerp(inactiveColor, Colors.white, 0.6);
        canvas.drawRRect(outer, innerFillPaint);
        _drawBorder(canvas, outer, t, paint);
      } else {
        canvas.drawRRect(outer, paint);

        _initStrokePaint(paint);
        final double tShrink = (t - 0.5) * 2.0;
        if (_oldValue == null)
          _drawDash(canvas, origin, tShrink, paint);
        else
          _drawCheck(canvas, origin, tShrink, paint);
      }
    } else {
      // Two cases: null to true, true to null
      final RRect outer = _outerRectAt(origin, 1.0);
      final Paint paint = Paint()..color = _colorAt(1.0);
      canvas.drawRRect(outer, paint);

      _initStrokePaint(paint);
      if (tNormalized <= 0.5) {
        final double tShrink = 1.0 - tNormalized * 2.0;
        if (_oldValue == true)
          _drawCheck(canvas, origin, tShrink, paint);
        else
          _drawDash(canvas, origin, tShrink, paint);
      } else {
        final double tExpand = (tNormalized - 0.5) * 2.0;
        if (value == true)
          _drawCheck(canvas, origin, tExpand, paint);
        else
          _drawDash(canvas, origin, tExpand, paint);
      }
    }
  }
}

register.dart

import 'package:flutter/material.dart';
import 'register_personal.dart';
import 'sequence.dart';
import 'package:sequence_indicator/global.dart' as global;

class RegisterPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _RegisterPageState();
}

class _RegisterPageState extends State<RegisterPage> {
  SequenceController _sequenceController = SequenceController(selectedIndex: 0);

  Function _onCompleted;

  @override
  void initState() {
    super.initState();

    _onCompleted = () {
      _sequenceController.selectedIndex =
          (_sequenceController.selectedIndex + 1).clamp(0, 4);

      if (_sequenceController.selectedIndex == 4) {
        print("Completed");
      }
    };
  }

  @override
  Widget build(BuildContext context) {
    Function titleGenerator = (String title) {
      return Container(
          constraints: BoxConstraints.expand(),
          alignment: Alignment.center,
          child: Text(
            title, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ));
    };

    return Scaffold(
      body: Sequence(
        size: 50.0,
        titleContentRatio: 0.2,
        controller: _sequenceController,
        lineColor: global.systemPrimaryColor,
        startColor: global.systemWhiteColor,
        endColor: global.systemGreenColor,
        children: [
          SequenceItem(
              indicator: Icon(Icons.person, color: Colors.white),
              title: titleGenerator("Personal Information"),
              content: RegisterPersonalPage(onCompleted: _onCompleted)),
          SequenceItem(
              indicator: Icon(Icons.work),
              title: titleGenerator("Additional Information"),
              content: RegisterPersonalPage(onCompleted: _onCompleted)),
          SequenceItem(
              indicator: Icon(Icons.home),
              title: titleGenerator("Flutter Information"),
              content: RegisterPersonalPage(onCompleted: _onCompleted)),
          SequenceItem(
              indicator: Icon(Icons.account_box),
              title: titleGenerator("Account Information"),
              content: RegisterPersonalPage(onCompleted: _onCompleted)),
        ],
      ),
    );
  }
}

register_personal.dart

import 'package:flutter/material.dart';

class RegisterPersonalPage extends StatefulWidget {
  final VoidCallback onCompleted;

  RegisterPersonalPage({this.onCompleted});

  @override
  State<StatefulWidget> createState() => _RegisterPersonalPageState();
}

class _RegisterPersonalPageState extends State<RegisterPersonalPage> {

  @override
  void initState() {
    super.initState();

  }
  @override
  Widget build(BuildContext context) {
    return Container(
        padding: EdgeInsets.symmetric(horizontal: 32.0)
            .copyWith(top: 0.0, bottom: 16.0),
        child: Column(children: <Widget>[
          Container(height: 40.0),
          RaisedButton(
              color: Colors.white,
              child: Text('Next'), onPressed: (){
            if (widget.onCompleted != null) widget.onCompleted();
//                controller.selectedIndex =
//                    (controller.selectedIndex + 1).clamp(0, 10);
          })
        ],));
  }
}

sequence.dart

import 'package:flutter/material.dart';
import 'package:sequence_indicator/global.dart' as global;
import 'adv_row.dart';
import 'mini_checkbox.dart';

const int _kEachItemDuration = 250;

class SequenceItem {
  final Widget indicator;
  final Widget title;
  final Widget content;

  SequenceItem({this.indicator, this.title, this.content})
      : assert(indicator != null),
        assert(title != null),
        assert(content != null);
}

class Sequence extends StatefulWidget {
  final List<SequenceItem> children;
  final double size;
  final Color lineColor;
  final Color startColor;
  final Color endColor;
  final double dividerWidth;
  final SequenceController controller;
  final double titleContentRatio;

  Sequence(
      {@required this.children,
      double size,
      Color lineColor,
      Color startColor,
      Color endColor,
      double dividerWidth,
      int selectedIndex,
      SequenceController controller,
      double titleContentRatio})
      : assert(selectedIndex == null || controller == null),
        this.size = size ?? 40.0,
        this.lineColor = lineColor ?? global.systemBlueColor,
        this.startColor = startColor ?? global.systemYellowColor,
        this.endColor = lineColor ?? global.systemGreenColor,
        this.dividerWidth = dividerWidth ?? 20.0,
        this.controller =
            controller ?? SequenceController(selectedIndex: selectedIndex ?? 0),
        this.titleContentRatio = titleContentRatio ?? 0.3;

  @override
  State<StatefulWidget> createState() => _SequenceState();
}

class _SequenceState extends State<Sequence> with TickerProviderStateMixin {
  AnimationController mainController;
  Animation<double> scale;
  List<Animation<double>> scaleAnimations = [];
  Animation<double> width;
  List<Animation<Color>> colorAnimations = [];
  List<AnimationController> colorControllers = [];
  List<AnimationController> borderControllers = [];
  List<Animation<double>> checkboxScaleAnimations = [];

  @override
  void dispose() {
    super.dispose();
    mainController.dispose();
    for (AnimationController borderController in borderControllers)
      borderController.dispose();
    for (AnimationController colorController in colorControllers)
      colorController.dispose();
    _pageController.dispose();
    _bodyPageController.dispose();
    _scrollController.dispose();
  }

  @override
  void initState() {
    super.initState();
    int totalItem = widget.children.length;

    int totalDuration = 300 + (_kEachItemDuration * totalItem);

    mainController = AnimationController(
        duration: Duration(milliseconds: totalDuration), vsync: this);

    double totalPortion = 0.5;

    for (int i = 0; i < totalItem; i++) {
      double portion = 0.5 / totalItem;
      double beginPortion = totalPortion;
      double endPortion = (totalPortion + portion).clamp(0.0, 1.0);

      Animation<double> scaleAnimation = Tween<double>(
        begin: 0.0,
        end: 1.0,
      ).animate(
        CurvedAnimation(
          parent: mainController.view,
          curve: Interval(
            beginPortion,
            endPortion,
            curve: Curves.ease,
          ),
        ),
      );

      totalPortion += portion;

      scaleAnimations.add(scaleAnimation);

      AnimationController colorController = AnimationController(
          duration: Duration(milliseconds: 200), vsync: this);

      Animation<Color> colorAnimation = ColorTween(
        begin: widget.startColor,
        end: widget.endColor,
      ).animate(colorController);

      Animation<double> checkboxScaleAnimation = Tween<double>(
        begin: 0.0,
        end: 1.0,
      ).animate(colorController);

      colorController.addListener(() {
        setState(() {});
      });

      colorControllers.add(colorController);
      colorAnimations.add(colorAnimation);
      checkboxScaleAnimations.add(checkboxScaleAnimation);

      AnimationController borderController = AnimationController(
          duration: Duration(milliseconds: 200), vsync: this);

      borderController.addListener(() {
        setState(() {});
      });

      borderControllers.add(borderController);
    }

    width = Tween<double>(
      begin: 0.0,
      end: 1.0,
    ).animate(
      CurvedAnimation(
        parent: mainController.view,
        curve: Interval(
          0.0,
          0.5,
          curve: Curves.ease,
        ),
      ),
    );

    mainController.forward();

    for (int i = 0; i <= widget.controller.selectedIndex; i++) {
      if (i < borderControllers.length) borderControllers[i].forward();
      if (i < widget.controller.selectedIndex) colorControllers[i].forward();
    }

    widget.controller.addListener(() {
      double startSupposeScroll =
          ((widget.controller.selectedIndex) * widget.size) +
              ((widget.controller.selectedIndex) * widget.dividerWidth);
      double endSupposeScroll =
          ((widget.controller.selectedIndex + 1) * widget.size) +
              ((widget.controller.selectedIndex + 2) * widget.dividerWidth);
      double startVisiblePosition = _scrollController.offset;
      double endVisiblePosition = _scrollController.offset + _maxWidth;

      if (_scrollController.hasClients) {
        if (endSupposeScroll > endVisiblePosition) {
          _scrollController.animateTo(
              (endSupposeScroll - _maxWidth)
                  .clamp(0.0, _scrollController.position.maxScrollExtent),
              duration: Duration(milliseconds: 200),
              curve: Curves.ease);
        } else if (startSupposeScroll < startVisiblePosition) {
          _scrollController.animateTo(
              (startSupposeScroll)
                  .clamp(0.0, _scrollController.position.maxScrollExtent),
              duration: Duration(milliseconds: 200),
              curve: Curves.ease);
        }
      }
      if (widget.controller.selectedIndex < widget.children.length) {
        _pageController.animateToPage(widget.controller.selectedIndex,
            duration: Duration(milliseconds: 200), curve: Curves.ease);
        _bodyPageController.animateToPage(widget.controller.selectedIndex,
            duration: Duration(milliseconds: 200), curve: Curves.ease);
      }

      for (int i = 0; i <= widget.controller.selectedIndex; i++) {
        int total = widget.children.length;

        for (int j = 0; j < total; j++) {
          if (i - 1 >= j) {
            colorControllers[j].forward();
          } else {
            colorControllers[j].reverse();
          }

          if (i >= j) {
            borderControllers[j].forward();
          } else {
            borderControllers[j].reverse();
          }
        }
      }
    });

    _pageController =
        PageController(initialPage: widget.controller.selectedIndex);

    _bodyPageController =
        PageController(initialPage: widget.controller.selectedIndex);
  }

  double _maxWidth = 0.0;

  PageController _pageController;
  PageController _bodyPageController;
  ScrollController _scrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        int total = widget.children.length;
        double maxHeight = constraints.maxHeight;
        _maxWidth = constraints.maxWidth;

        return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
          Stack(children: [
            Container(
              height: maxHeight * widget.titleContentRatio,
              child: PageView(
                  controller: _pageController,
                  physics: NeverScrollableScrollPhysics(),
                  children: widget.children.map((SequenceItem item) {
                    return item.title;
                  }).toList()),
            ),
            Container(
              height: maxHeight * (1.0 - widget.titleContentRatio),
              margin:
                  EdgeInsets.only(top: maxHeight * widget.titleContentRatio),
              child: PageView(
                  controller: _bodyPageController,
                  physics: NeverScrollableScrollPhysics(),
                  children: widget.children.map((SequenceItem item) {
                    return item.content;
                  }).toList()),
            ),
            Positioned(
                bottom: maxHeight * (1.0 - widget.titleContentRatio) -
                    ((widget.size / 2) + ((widget.size * 0.375 / 2) + 4.0)),
                left: 0.0,
                right: 0.0,
                child: AnimatedBuilder(
                  builder: (context, child) {
                    List<Widget> children = [];

                    for (int i = 0; i < total; i++) {
                      double borderWidth = widget.size * 0.1;
                      double borderRadiusSize = widget.size * 0.0;
                      SequenceItem child = widget.children[i];
                      Widget indicator;
                      if (child.indicator is Icon) {
                        Icon transitionIcon = child.indicator as Icon;
                        Color color = Color.lerp(widget.endColor,
                            widget.startColor, colorControllers[i].value);

                        indicator = Icon(transitionIcon.icon, color: color);
                      } else{
                        indicator = child.indicator;
                      }

                      children.add(ScaleTransition(
                        scale: scaleAnimations[i],
                        child: Stack(alignment: Alignment.center, children: [
                          Container(
                            height: widget.size,
                            width: widget.size, //colorAnimations[i].value,
                            decoration: BoxDecoration(
                              borderRadius:
                                  BorderRadius.circular(borderRadiusSize),
                              color: widget.endColor,
                            ),
                          ),
                          Container(
                            height: widget.size -
                                (borderWidth * borderControllers[i].value) +
                                (borderWidth * colorControllers[i].value),
                            width: widget.size -
                                (borderWidth * borderControllers[i].value) +
                                (borderWidth * colorControllers[i].value),
                            decoration: BoxDecoration(
                              borderRadius:
                                  BorderRadius.circular(borderRadiusSize),
                              color: colorAnimations[i].value,
                            ),
                          ),
                          Opacity(
                            child: indicator,
                            opacity: 1.0,
                          ),
                          Positioned(
                              bottom: 0.0,
                              right: 0.0,
                              child: ScaleTransition(
                                  scale: checkboxScaleAnimations[i],
                                  child: MiniCheckbox(
                                    value: widget.controller.selectedIndex > i,
                                    activeColor:
                                        widget.controller.selectedIndex >= i
                                            ? Color.lerp(Colors.orange,
                                                Colors.orange, 0.1)
                                            : Color.lerp(widget.startColor,
                                                Colors.black87, 0.4),
                                    inactiveColor:
                                        widget.controller.selectedIndex >= i
                                            ? Color.lerp(widget.endColor,
                                                Colors.black87, 0.4)
                                            : Color.lerp(widget.startColor,
                                                Colors.black87, 0.4),
                                    size: borderControllers[i].value *
                                        (widget.size * 0.375),
                                    vsync: this,
                                  ))),
                          Opacity(
                              opacity: 0.5,
                              child: Material(
                                  color: Colors.transparent,
                                  clipBehavior: Clip.antiAlias,
                                  borderRadius:
                                      BorderRadius.circular(borderRadiusSize),
                                  child: InkWell(
                                    child: Container(
                                      height: widget.size -
                                          (borderWidth *
                                              borderControllers[i].value) +
                                          (borderWidth *
                                              colorControllers[i].value),
                                      width: widget.size -
                                          (borderWidth *
                                              borderControllers[i].value) +
                                          (borderWidth *
                                              colorControllers[i].value),
                                    ),
                                    onTap: () {
                                      if (widget.controller.selectedIndex >= i)
                                      widget.controller.selectedIndex = i;
                                    },
                                  ))),
                        ]),
                      ));
                    }
                    return Stack(children: [
                      Positioned(
                          top: (widget.size - 5.0) / 2.0,
                          height: 3.0,
                          child: Container(
                              height: 5.0,
                              width: width.value * _maxWidth,
                              color: widget.lineColor)),
                      SingleChildScrollView(
                        controller: _scrollController,
                        scrollDirection: Axis.horizontal,
                        child: Builder(builder: (context) {
                          return Container(
                              width:
                                  (_scrollController.position.maxScrollExtent ??
                                              1.0) >
                                          0.0
                                      ? null
                                      : _maxWidth,
                              child: AdvRow(
                                  margin: EdgeInsets.only(
                                      bottom: (widget.size * 0.375 / 2) + 4.0),
                                  divider: RowDivider(widget.dividerWidth),
                                  mainAxisAlignment: MainAxisAlignment.center,
                                  children: children));
                        }),
                      )
                    ]);
                  },
                  animation: mainController.view,
                )),
          ]),
        ]);
      },
    );
  }
}

class SequenceController extends ValueNotifier<SequenceEditingValue> {
  int get selectedIndex => value.selectedIndex;

  set selectedIndex(int newSelectedIndex) {
    value = value.copyWith(selectedIndex: newSelectedIndex);
  }

  SequenceController({int selectedIndex})
      : super(selectedIndex == null
            ? SequenceEditingValue.empty
            : new SequenceEditingValue(selectedIndex: selectedIndex));

  SequenceController.fromValue(SequenceEditingValue value)
      : super(value ?? SequenceEditingValue.empty);

  void clear() {
    value = SequenceEditingValue.empty;
  }
}

@immutable
class SequenceEditingValue {
  const SequenceEditingValue({this.selectedIndex});

  final int selectedIndex;

  static const SequenceEditingValue empty = const SequenceEditingValue();

  SequenceEditingValue copyWith({int selectedIndex}) {
    return new SequenceEditingValue(
        selectedIndex: selectedIndex ?? this.selectedIndex);
  }

  SequenceEditingValue.fromValue(SequenceEditingValue copy)
      : this.selectedIndex = copy.selectedIndex;

  @override
  String toString() => '$runtimeType(selectedIndex: $selectedIndex)';

  @override
  bool operator ==(dynamic other) {
    if (identical(this, other)) return true;
    if (other is! SequenceEditingValue) return false;
    final SequenceEditingValue typedOther = other;
    return typedOther.selectedIndex == selectedIndex;
  }

  @override
  int get hashCode => selectedIndex.hashCode;
}

main.dart

import 'package:flutter/material.dart';

import 'register.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: RegisterPage(),
    );
  }
}

The flutter tutorial  is a website that bring you the latest and amazing resources of code. All the languages codes are included in this website. The languages like flutter, android, java,kotlin etc.with the help of this languages any user can develop the beautiful application

For more information about Flutter. visit www.fluttertutorial.in