Flutter开发之PageView指示器(31)

移动开发中圆点指示器给用户很好的用户体验,iOS 有自己的控件UIPageControl 方便快捷实现。既然想用Flutter代替,就想着如何实现UIPageControl 类似的功能。这篇文章就在前辈的基础上,实战一下PageView指示器。来实现圆点指示器的功能。(文章结尾会贴上参考的文章)

先看一下效果

在这里插入图片描述

完整代码:

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

class PageControlTest extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('DemoList'),
      ),
      body: new MyHomePage(),
    );
  }
}

/// An indicator showing the currently selected page of a PageController
class DotsIndicator extends AnimatedWidget {
  DotsIndicator({
    this.controller,
    this.itemCount,
    this.onPageSelected,
    this.color: Colors.white,
  }) : super(listenable: controller);

  /// The PageController that this DotsIndicator is representing.
  final PageController controller;

  /// The number of items managed by the PageController
  final int itemCount;

  /// Called when a dot is tapped
  final ValueChanged<int> onPageSelected;

  /// The color of the dots.
  ///
  /// Defaults to `Colors.white`.
  final Color color;

  // The base size of the dots
  static const double _kDotSize = 8.0;

  // The increase in the size of the selected dot
  static const double _kMaxZoom = 2.0;

  // The distance between the center of each dot
  static const double _kDotSpacing = 25.0;

  Widget _buildDot(int index,int pageCount) {
    // 当前位置
    double currentPosition =
    ((controller.page ?? controller.initialPage.toDouble()) %
        pageCount.toDouble());

    // 计算变化曲线
    double selectedness = Curves.easeOut.transform(
      max(
        0.0,
        1.0 - (currentPosition - index).abs(),
      ),
    );

    // 从0点跳到最后一个时状态需要特殊处理
    if (currentPosition > pageCount - 1 && index == 0) {
      selectedness = 1 - (pageCount.toDouble() - currentPosition);
    }

    print('selectedness $index');
    print('selectedness $selectedness');
    print('selectedness $controller.page');
    print('selectedness $controller.initialPage');

    // 计算缩放大小
    double zoom = 1.0 + (_kMaxZoom - 1.0) * selectedness;
    return new Container(
      width: _kDotSpacing,
      child: new Center(
        child: new Material(
          color: color,
          type: MaterialType.circle,
          child: new Container(
            width: _kDotSize * zoom,
            height: _kDotSize * zoom,
            child: new InkWell(
              onTap: () => onPageSelected(index),
            ),
          ),
        ),
      ),
    );
  }

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

class MyHomePage extends StatefulWidget {
  @override
  State createState() => new MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  final _controller = new PageController();
  static const _kDuration = const Duration(milliseconds: 300);
  static const _kCurve = Curves.ease;
  final _kArrowColor = Colors.black.withOpacity(0.8);

  final List<Widget> _pages = <Widget>[
    new ConstrainedBox(
      constraints: const BoxConstraints.expand(),
      child: new FlutterLogo(colors: Colors.blue),
    ),
    new ConstrainedBox(
      constraints: const BoxConstraints.expand(),
      child: new FlutterLogo(style: FlutterLogoStyle.stacked, colors: Colors.red),
    ),
    new ConstrainedBox(
      constraints: const BoxConstraints.expand(),
      child: new FlutterLogo(style: FlutterLogoStyle.horizontal, colors: Colors.green),
    ),
  ];

  @override
  Widget build(BuildContext context) {

    return new Scaffold(
//      appBar: new AppBar(
//        title: new Text('PageControl'),
//      ),

      body: Center(
          child:new IconTheme(
            data: new IconThemeData(color: _kArrowColor),
            child: new Stack(
              children: <Widget>[
                new PageView.builder(
                  physics: new AlwaysScrollableScrollPhysics(),
                  controller: _controller,
                  itemBuilder: (BuildContext context, int index) {
                    return _pages[index % _pages.length];
                  },
                ),
                new Positioned(
                  bottom: 0.0,
                  left: 0.0,
                  right: 0.0,
                  child: new Container(
                    color: Colors.grey[800].withOpacity(0.5),
                    padding: const EdgeInsets.all(20.0),
                    child: new Center(
                      child: new DotsIndicator(
                        controller: _controller,
                        itemCount: _pages.length,
                        onPageSelected: (int page) {
                          _controller.animateToPage(
                            page,
                            duration: _kDuration,
                            curve: _kCurve,
                          );
                        },
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
      )
    );
  }
}
BannerGalleryInFlutter

这是一个多样化定制的轮播图,实现无限滑动Banner。
在这里插入图片描述

参考文章

Flutter pageview切换指示器
flutter PageView实现左右滑动切换视图

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值