欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Flutter pageview指示器(indicator)实现

程序员文章站 2024-02-05 20:44:16
...

最近正好用到pageview,发现官方好像没有提供指示器。去pub上搜了一下indicator,点了star最多的一个看了下,发现他的刷新是连pageview一起刷新的,和我需要的不匹配。最后还是决定自己实现一下吧。

效果图

Flutter pageview指示器(indicator)实现

项目地址

flutter_page_indicator

源码

pub上的项目indicator圆点好像都是用paint画的。

我的第一印象其实就是最外层用Stack包裹,里面放普通圆点和当前位置圆点。

下层普通的圆点用一个ListView,ListView上层放一个表示当前进度的小圆点用Container表示。当位置发生改变,我们只需要修改上层Container的位置就可以了。

使用Decoration来修改圆点属性

1、创建一个PageIndicator
class PageIndicator extends StatefulWidget {

  ///PageView 子view集合的长度
  final int length;

  ///PageController
  final PageController pageController;

  ///默认颜色
  final Color defaultColor;

  ///默认宽度
  final double defaultWidth;

  ///默认高度
  final double defaultHeight;

  ///默认Decoration
  final Decoration defaultDecoration;

  ///当前颜色
  final Color currentColor;

  ///当前宽度
  final double currentWidth;

  ///当前高度
  final double currentHeight;

  ///当前Decoration
  final Decoration currentDecoration;

  ///间距
  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();
  }
}

PageIndicator声明了一些变量,除了lengthpageController是必须的,其它都有默认值。

2、创建_PageState类

在PageIndicator构造方法中我们传入了PageController ,这样只需要在initState给PageController添加一个addListener监听就可以获得当前pageview的page值。然后调用setState(() {});刷新即可。

在pageview滑动的时候,我们真正需要改变的其实是上层表示进度的圆点,所以我们不需要使用setState(() {});来刷新整个指示器,只需要单独刷新表示进度的圆点就行了。这里使用StreamBuilder来完成局部刷新

_PageState源码如下:

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,
            ///普通圆点用ListView显示
            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刷新
            child: StreamBuilder<double>(
                stream: _streamController.stream,
                initialData: 0,
                builder: (context, snapshot) {
                  ///表示当前进度的圆点
                  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();
  }
}

使用

pubspec.yaml引入:

dependencies:
  pageview_indicator_plugins: ^0.0.2

1、默认使用的话只需要传递pageview children的长度和pageController就行了。

PageIndicator(
     length: 6,
     pageController: pageController,
)

2、也可以通过修改选中圆点的宽高和修改Decoration属性来修改圆点属性

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

github地址:

https://github.com/Zhengyi66/flutter_page_indicator

相关标签: Flutter开发