在移动端轮播图是比较常见的一种UI布局,在web端实现起来比较简单,了解flutter一段时间后,想用flutter撸一个轮播图出来,苦于无从下手(对flutter的内置组件还不是很熟悉),最后参考了其他的大佬文章,才有了思路,这里做一个小小的技术积累。
效果图
1.了解需求
- 轮播图具有自动翻页
- 可以手势拖动翻页,点击事件
- 有个指示器
- 轮播图的一些基础属性,高度等
2.通用Banner组件设计
一般如果是项目通用的banner的话,需要设计一些比较通用的配置属性项,再其他页面也能够很轻松的使用,比如轮播图的高度,点击事件的回调函数,切换的动画效果,切换的时间间隔等。
2.1 定义一个CustomBanner类
// 构造函数
CustomBanner(
this._images,
{
this.height = 200,
this.onTap,
this.curve = Curves.linear,
this.timeSeconds = 3,
}
) : asset(_images != null);
-
_images
: 给组件传一个图片的链接列表 -
height
: 组件的高度,默认值是200 -
onTap
:点击的回调函数,回调传了一个ValueChange<int>
,当前的点击的下标 -
curve
: 切换的动画 -
timeSeconds
: 切换的时间间隔
2.2 使用flutter内置Widget PageView
有轮播切换效果的Widget,flutter已经内置有了PageView
,这个Widget是可以左右切换页面的效果,能够满足我们的需求。
- 定义一个PageView Widget
Widget _buildPageView() {
return new Container(
height: widget.height, // 组件高度
child: PageView.builder( // 使用builder是可以创建一个无限滚动的页面
onPageChange: (index) {
setState(() {
_curIndex = index;
if (index == 0) {
_curIndex = length;
}
})
},
itemBuilder: (BuildContext context, int index) {
return Image.network(
widget._images[index % length],
fit: BoxFit.cover,
),
});
),
);
}
-
左边无限循环切换:
在onPageChange事件中,当index == 0的时候,把 _curIndex = length;在itemBuilder中返回的每一项是当前的index对图片数组取余,再往左滑动的时候,当滑到index为0,那么下一张应该是length-1,length-1的下一张是0,所以需要把_curIndex = length,同时需要_pageController.jumpToPage(_curIndex);
页面切换到最后一张的下一张,然后就能往左无限的滑动了。
添加轮播指示器_buildIndicator
在最外层用Stack Widget
包裹_buildPageView
和_buildIndicator
;新创建的_buildIndicator
定位到底部,具体代码如下:
Widget _buildIndicator() {
return Positioned(
bottom: 10,
child: Row(
children: widget._images.map((s) {
padding: const EdgeInsets.symmetric(horizontal: 3.0), // 水平padding
child: ClipOval( // 原型can'j
child: Container(
width: 8,
height: 8,
color: s == widget._images[_curIndex % length] ? Colors.white : Colors.grey,
), // 当前元素等于图片中显示的元素的时候,是白色圆点,否则是灰色
),
}).toList()
)
)
}
在PageView
onPageChanged
后,setState _curIndex 的值,这样指示器就能跟着图片一起变动。
2.3 让图片自动切换
上面的一些操作之后,基本上功能已经实现,手动可以无限切换轮播,那么自动轮播的话,这里需要用到flutter的Timer
- 初始化数据定义一个Timer
利用Timer.periodic()
来创建一个循环定时任务,这个相当于web的setInterval
, 回调函数是达到间隔后执行的函数
_initTimer() {
if (_timer == null) {
_timer = Timer.periodic(Duration(seconds: widget.timeSeconds), (t) {
_curIndex++;
_pageController.animateToPage( // 动画切换
_curIndex,
duration: Duration(milliseconds: 300),
curve: Curves.linear,
);
});
}
}
到这里基本上一个轮播组件就基本上完成了,点击事件的添加,在图片外层加一个GestureDetector
手势,添加onTap事件;本来想着在图片滑动时去清掉定时任务,滑动结束后再重新初始化定时任务的,但是好像PageView和手势有冲突,只执行了onPanDown
,onPanUpdate
和onPanEnd
不会触发。所以解决方案是在onPanDown时Timer.cancel清除定时,然后再初始化定时任务。
- 用法
body: Column(
children: <Widget>[
CustomBanner(_images),
new Container(
padding: const EdgeInsets.only(top: 10.0),
child: CustomBanner(_images1, timeSeconds: 1),
),
],
)
总结
通过做一个flutter的轮播图,对dart语法又有了更加深入的了解,对flutter自定义组件的封装,布局,常用的Widget也有了一定的了解。