您的位置:首页 > 移动开发

Flutter跨平台移动端开发丨封装轮播部件 Banner Widget

2020-01-14 12:26 369 查看

移动端开发过程中 Banner 组件非常常见,项目中用的到就封装了一个,主要用到 Timer + PageView,采用定时轮播的方法实现,可设置展示时间、切换速度等

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);
}

}

运行结果

  • 点赞 3
  • 收藏
  • 分享
  • 文章举报
MobMsg 发布了94 篇原创文章 · 获赞 390 · 访问量 1万+ 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: