用 Flutter 实现 PageView 指示器

本篇用一个PageView的实例来加深印象,并且在之后的专栏里,我们会深化这个示例,做成一个支持上下左右无限滑动的图片Banner,并且教你如何把他做成Dart library并且开放给其他人使用。
用 Flutter 实现 PageView 指示器

一.无限滑动的PageView

在实现PageView指示器之前,咱们需要先实现一个PageView。在Flutter中实现一个PageView很简单。

class BannerGalleryWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return BannerGalleryWidgetState();
  }
}

class BannerGalleryWidgetState extends State<BannerGalleryWidget> {
  final PageController controller = PageController(initialPage: 200);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
        height: 250.0,
        child: Container(
          color: Colors.grey,
          child: PageView.builder(
            controller: controller,
            itemBuilder: (context, index) {
              return new Center(
                child: new Text('页面 ${index}'),
              );
            },
          ),
        ));
  }
}

以上代码会得出这样一个界面。稍微解释一下代码:

/// 指定一个控制器,用来控制PageView的滑动,以及初始位置在第200页
/// 主要为了实现“无限循环”
final PageController controller = PageController(initialPage: 200);

/// 一个固定大小的容器,这里指定了他的高为250
SizedBox(height: 250.0)
/// 一个容器,用来设定背景颜色为灰色
Container(color: Colors.grey)
/// 主角PageView,文字居中显示当前的索引。
PageView.builder(
            controller: controller,
            itemBuilder: (context, index) {
              return new Center(
                child: new Text('页面 ${index}'),
              );},),

二.实现一个指示器

有了无限滑动的PageView之后,咱们再来关联一个指示器:

class Indicator extends StatelessWidget {
  Indicator({
    this.controller,
    this.itemCount: 0,
  }) : assert(controller != null);

  /// PageView的控制器
  final PageController controller;

  /// 指示器的个数
  final int itemCount;

  /// 普通的颜色
  final Color normalColor = Colors.blue;

  /// 选中的颜色
  final Color selectedColor = Colors.red;

  /// 点的大小
  final double size = 8.0;

  /// 点的间距
  final double spacing = 4.0;

  /// 点的Widget
  Widget _buildIndicator(
      int index, int pageCount, double dotSize, double spacing) {
    // 是否是当前页面被选中
    bool isCurrentPageSelected = index ==
        (controller.page != null ? controller.page.round() % pageCount : 0);

    return new Container(
      height: size,
      width: size + (2 * spacing),
      child: new Center(
        child: new Material(
          color: isCurrentPageSelected ? selectedColor : normalColor,
          type: MaterialType.circle,
          child: new Container(
            width: dotSize,
            height: dotSize,
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return new Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: new List<Widget>.generate(itemCount, (int index) {
        return _buildIndicator(index, itemCount, size, spacing);
      }),
    );
  }
}

这段代码比较简单,在build()方法里面构建了一个横向的List。
List的Item是一个固定大小的圆点,选中是一种颜色,没有选中是另一种颜色。

三.关联PageView和指示器

class BannerGalleryWidgetState2 extends State<BannerGalleryWidget2> {
  final PageController controller = PageController(initialPage: 200);

  void _pageChanged(int index) {
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        SizedBox(
            height: 150.0,
            child: Container(
              color: Colors.grey,
              child: PageView.builder(
                onPageChanged: _pageChanged,
                controller: controller,
                itemBuilder: (context, index) {
                  return new Center(
                    child: new Text('页面 ${index}'),
                  );
                },
              ),
            )),
        Indicator(
          controller: controller,
          itemCount: 5,
        ),
      ],
    );
  }
}

把布局容器改一下,用一个列包裹PageView和Indicator,给PageView加一个onPageChanged,检查当页面修改的时候setState()刷新UI就好了。

四.总结
至此,无限滑动的PageView指示器已经完成了,虽然看起来和专栏一开始的示例图片有点小小的差别,但是至少需求实现了。但是现在这个指示器还比较傻,比如选中之后才会变色,而且不会放大显示。在之后的专栏里我教大家如何完善这个指示器以及提供整个工程的完整代码,敬请期待。

猜你喜欢

转载自blog.51cto.com/14332859/2420438