美文网首页Flutter
Flutter跨平台移动端开发丨封装轮播部件 Banner Wi

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

作者: MobMsg | 来源:发表于2019-07-03 22:09 被阅读0次

    移动端开发过程中 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);
      }
    
    }
    

    运行结果

    相关文章

      网友评论

        本文标题:Flutter跨平台移动端开发丨封装轮播部件 Banner Wi

        本文链接:https://www.haomeiwen.com/subject/rdpchctx.html