移动开发中圆点指示器给用户很好的用户体验,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实现左右滑动切换视图