移动端开发过程中 Banner 组件非常常见,项目中用的到就封装了一个,主要用到 Timer + PageView,采用定时轮播的方法实现,可设置展示时间、切换速度等
![](https://img.haomeiwen.com/i9791228/db35d5ceeec6c46f.gif)
Banner Widget
可设置 banner 高度、图片展示时间、图片切换速度,如需其它支持可自行添加、更改
import 'package:flutter/material.dart';
import 'dart:async';
import 'BannerBean.dart';
import 'package:meta/meta.dart';
/**
* @des banner 部件
* @author liyongli 20190702
* */
class BannerWidget extends StatefulWidget{
// banner 数据实体集合
List<BannerBean> bannerData;
// banner 默认高度
double bannerHeight;
// banner 默认展示时间(毫秒)
int bannerDuration;
// banner 切换速度(毫秒)
int bannerSwitch;
// 图片加载器
Build bannerBuild;
// 点击事件回调接口
OnBannerPress bannerPress;
BannerWidget(
{Key key,
@required this.bannerData,
this.bannerHeight,
this.bannerDuration,
this.bannerSwitch,
this.bannerPress,
this.bannerBuild})
: super(key: key);
@override
State<StatefulWidget> createState() => BannerWidgetState();
}
/**
* @des banner 部件 State
* @author liyongli 20190702
* */
const CountMax = 0x7fffffff;
typedef void OnBannerPress(int position, BannerBean entity);
typedef Widget Build(int position, BannerBean entity);
class BannerWidgetState extends State<BannerWidget>{
// 定时器
Timer bannerTimer;
// 当前 banner 页下标
int bannerIndex = 0;
// 控制器
PageController bannerController;
@override
void initState() {
super.initState();
double current = (CountMax / 2) - ((CountMax / 2) % widget.bannerData.length);
bannerController = PageController(initialPage: current.toInt());
}
@override
Widget build(BuildContext context) {
return Container(
height: widget.bannerHeight,
color: Colors.white,
child: Stack(
children: <Widget>[
viewPages(),
viewTips()
],
),
);
}
/**
* banner 图片组件
* */
Widget viewPages(){
return PageView.builder(
itemCount: CountMax,
controller: bannerController,
onPageChanged: onPageChanged,
itemBuilder: (context, index){
return InkWell(
onTap: (){
if(null != widget.bannerPress){
widget.bannerPress(bannerIndex, widget.bannerData[bannerIndex]);
}
},
child: widget.bannerBuild == null ? FadeInImage.memoryNetwork( image: widget.bannerData[index % widget.bannerData.length].bannerUrl, fit: BoxFit.fitWidth) : widget.bannerBuild(index, widget.bannerData[index % widget.bannerData.length])
);
},
);
}
/**
* 更新坐标与图片
* */
void onPageChanged(index){
bannerIndex = index % widget.bannerData.length;
setState(() {});
}
/**
* banner 小原点组件
* */
Widget viewTips(){
if(widget.bannerData.length <= 1){
return Align();
}
return Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 32.0,
padding: EdgeInsets.all(5.0),
color: Colors.black,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(widget.bannerData[bannerIndex].bannerTitle, style: TextStyle(color: Colors.white)),
Row(children: bannerCircle(),)
],
),
),
);
}
/**
* 绘制小圆点并组成集合返回
* */
List<Widget> bannerCircle(){
List<Widget> circleList = [];
for(var i = 0 ; i < widget.bannerData.length ; i++){
circleList.add(
Container(
margin: EdgeInsets.all(3.0),
width: 5.0,
height: 5.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: bannerIndex == i ? Colors.deepOrange : Colors.white,
),
)
);
}
return circleList;
}
/**
* 启动计时器
* */
void start(){
if(null != bannerTimer && bannerTimer.isActive){
stop();
}
if(null == widget.bannerData || widget.bannerData.length <= 1){
return;
}
bannerTimer = Timer.periodic(Duration(milliseconds: widget.bannerDuration), (bannerTimer){
bannerController.animateToPage(bannerController.page.toInt() + 1, duration: Duration(milliseconds: widget.bannerSwitch), curve: Curves.linear);
});
}
/**
* 停止计时器
* */
void stop(){
bannerTimer?.cancel();
bannerTimer = null;
}
/**
* 释放资源
* */
@override
void dispose() {
stop();
bannerController?.dispose();
super.dispose();
}
}
/**
* @des banner 组件抽象类
* @author liyongli 20190702
* */
abstract class BannerBeanUtils{
// 获取 banner 地址
get bannerUrl;
// 获取 banner 介绍
get bannerTitle;
}
Banner Widget 数据实体
可设置图片加载地址、图片配文、图片跳转参数等
import 'package:delongzhixuan/utils/banner/BannerWidget.dart';
/**
* @des banner 组件实体类
* @author liyongli 20190702
* */
class BannerBean extends Object with BannerBeanUtils{
String imageUrl;
String titleStr;
int intentType;
BannerBean({this.imageUrl, this.titleStr, this.intentType});
@override
get bannerTitle => titleStr;
@override
get bannerUrl => imageUrl;
}
Banner Widget 如何应用
本实例展示加载本地图片
import 'dart:async';
import 'dart:core';
import 'package:delongzhixuan/utils/banner/BannerBean.dart';
import 'package:delongzhixuan/utils/banner/BannerWidget.dart';
import 'package:flutter/material.dart';
/**
* @des 首页
* @author liyongli
* */
class MainHome extends StatefulWidget {
@override
State<StatefulWidget> createState() => new _MainHomeState();
}
/**
* @des 首页 State
* @author liyongli
* */
class _MainHomeState extends State<MainHome> {
@override
Widget build(BuildContext context) {
return _initWidget(context);
}
// 跨域访问
GlobalKey<BannerWidgetState> globalKey = new GlobalKey<BannerWidgetState>();
// banner 数据集合
List<BannerBean> bannerData;
/**
* 初始化 widget
* */
Widget _initWidget(BuildContext context){
return new Scaffold(
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
// banner 部分
Container(
width: double.maxFinite,
height: 260.0,
color: Colors.white,
child: BannerWidget( // 自定义 banner widget
key: globalKey, // 跨域访问目标
bannerData: _initBannerData(), // 数据集合
bannerDuration: 5000, // 展示时间
bannerSwitch: 500, // 切换耗时
bannerPress: _bannerPress, // 点击事件监听
bannerBuild: (position, BannerBean){ // 加载器
return Image.asset(BannerBean.bannerUrl, fit: BoxFit.fitWidth);
}
),
),
],
),
)
);
}
/**
* 初始化 banner 数据
* */
List<BannerBean> _initBannerData(){
List<BannerBean> bannerList = [
new BannerBean(imageUrl:"images/main_banner01.png", titleStr: "main_banner01", intentType: 0),
new BannerBean(imageUrl:"images/main_banner01.png", titleStr: "main_banner02", intentType: 0),
new BannerBean(imageUrl:"images/main_banner01.png", titleStr: "main_banner03", intentType: 0),
];
// 2 秒后启动轮播
Timer timer;
timer = new Timer(new Duration(seconds: 2), () {
globalKey.currentState.start();
timer.cancel();
timer = null;
});
return bannerList;
}
/**
* banner 点击事件监听
* */
void _bannerPress(int position, BannerBean entity){
print(position);
print(entity.titleStr + entity.imageUrl);
}
}
运行结果
![](https://img.haomeiwen.com/i9791228/db35d5ceeec6c46f.gif)
网友评论