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
- 收藏
- 分享
- 文章举报
相关文章推荐
- Flutter跨平台移动端开发丨封装顶部导航栏部件 TabBar Widget
- Flutter跨平台移动端开发丨Container + FlatButton 实现背景色渐变的圆角Button
- Flutter跨平台移动端开发丨TextField 添加背景色
- Flutter跨平台移动端开发丨持续更新的常用效果集锦
- 安卓开发笔记(三十二):banner轮播图的实现
- Android app 实现AppWidget 窗口部件开发
- 【转】跨平台移动端开发框架NativeScript 发布正式版本
- VS2013下实现移动端的跨平台开发
- arcgis api for js开发(二):widget窗口部件的使用之basemaptoggle底图切换
- Flutter完整开发实战详解(六、 深入Widget原理)
- Android 封装自定义无限轮播banner之体验装饰模式
- Android:手把手带你入门跨平台UI开发框架Flutter
- 何必苦等VS2015?来看看VS2013下实现移动端的跨平台开发
- Android开发中Banner部分实现真正的无限轮播
- 移动端跨平台开发的深度解析
- jquery简单的图片切换效果,支持pc端、移动端的banner图片切换开发
- 为什么移动端跨平台开发不靠谱?
- 跨平台移动端APP开发---简单高效的MUI框架
- 工作中封装的一些移动端轮播组件 用的是 vue写的 react后期有时间的话会补上
- 4.8.8 安卓开发笔记——自定义广告轮播Banner(无限循环实现)