Recently, I happened to use PageView, and found that there seems to be no indicator provided by the official. I searched indicator in pub and clicked the star with the largest number. I found that his refresh is refreshed together with PageView, which does not match what I need. I decided to do it myself.

rendering

The project address

flutter_page_indicator

The source code

The item Indicator on the pub seems to be painted in paint.

My first impression is that the outer layer of the Stack is wrapped with regular dots and dots in the current position.

The lower layer is a ListView, and the upper layer of the ListView is a Container representing the current progress. When the location changes, you only need to change the location of the upper-layer Container.

Modify dot properties using Decoration

1. Create onePageIndicatorclass

class PageIndicator extends StatefulWidget {

  ///PageView Specifies the length of the subview set
  final int length;

  ///PageController
  final PageController pageController;

  /// Default color
  final Color defaultColor;

  /// Default width
  final double defaultWidth;

  /// Default height
  final double defaultHeight;

  / / / the default Decoration
  final Decoration defaultDecoration;

  /// The current color
  final Color currentColor;

  /// The current width
  final double currentWidth;

  /// The current height
  final double currentHeight;

  / / / the current Decoration
  final Decoration currentDecoration;

  / / / spacing
  final double padding;
  PageIndicator({
    Key key,
    this.length,
    this.pageController,
    this.defaultColor = Colors.white,
    this.defaultWidth = 8.this.defaultHeight = 8.this.defaultDecoration,
    this.currentColor = Colors.grey,
    this.currentWidth = 8.this.currentHeight = 8.this.currentDecoration,
    this.padding = 8,
  }): assert(length ! =null), assert(pageController ! =null), super(key:key);

  @override
  State<StatefulWidget> createState() {
    return_PageState(); }}Copy the code

PageIndicator declares some variables, except length and pageController, which are required and all have default values.

Create the _PageState class

In the PageIndicator constructor we pass in the PageController so that we can get the page value of the current PageView simply by adding an addListener to the PageController at initState. Then call setState(() {}); Refresh.

When sliding pageView, what we really need to change is the upper layer of the progress dot, so we don’t need to use setState(() {}); To refresh the entire indicator, just refresh the progress dots individually. The StreamBuilder is used here to do the partial refresh

_PageState source code:

class _PageState extends State<PageIndicator> {

  StreamController _streamController;

  @override
  void initState() {
    super.initState();
    _streamController = StreamController<double> (); widget.pageController.addListener((){ _streamController.sink.add(widget.pageController.page); }); }@override
  Widget build(BuildContext context) {
    return Container(
      width: widget.normalWidth * widget.length +
          widget.padding * (widget.length + 1),
      height: widget.currentHeight,
      child: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          Positioned(
            left: 0,
            right: 0,
            top: 0,
            bottom: 0.// use ListView to display normal dots
            child: ListView.builder(
                scrollDirection: Axis.horizontal,
                itemCount: widget.length,
                physics: NeverScrollableScrollPhysics(),
                itemBuilder: (_, position) {
                  return Container(
                    width: widget.normalWidth,
                    height: widget.normalHeight,
                    margin: EdgeInsets.only(
                        left: widget.padding),
                    decoration: widget.normalDecoration ??
                        BoxDecoration(
                            color: widget.normalColor, shape: BoxShape.circle),
                  );
                }),
          ),
          Positioned(
            / / / StreamBuilder refresh
            child: StreamBuilder<double>(
                stream: _streamController.stream,
                initialData: 0,
                builder: (context, snapshot) {
                  /// A dot that represents the current progress
                  return Container(
                    width: widget.currentWidth,
                    height: widget.currentHeight,
                    decoration: widget.currentDecoration ?? BoxDecoration(
                        color: widget.currentColor, shape: BoxShape.circle),
                    margin: EdgeInsets.only(
                      left: left(snapshot.data),
                    ),
                  );
                }),
            left: 0() [(), (); }double left(double page){
    if(widget.currentWidth > widget.normalWidth){
      return widget.normalWidth * page + widget.padding*page + widget.padding - (widget.currentWidth - widget.normalWidth)/2;
    }else{
      return (widget.normalWidth * page + (page+1) * widget.padding); }}@override
  void dispose() {
    super.dispose();
    _streamController?.close();
  }
}

Copy the code

use

In Pubspec.yaml introduce:

dependencies:
  pageview_indicator_plugins: ^0.02.
Copy the code

1. By default, you only need to pass pageView Children’s length and pageController.

PageIndicator(
     length: 6,
     pageController: pageController,
)
Copy the code

2. You can also modify the width and height of the dot and modify the Decoration property

PageIndicator(
        length: 6,
        pageController: secondController,
        currentWidth: 16,
        currentDecoration: BoxDecoration(
        	color: Colors.cyanAccent,
       		borderRadius: BorderRadius.circular(10)))Copy the code

Making address:

Github.com/Zhengyi66/f…