flutter自定义广告Banner

2023-10-31

Flutter 1.0 is out!

Tuesday, December 4, 2018

Banner是手机应用最常见的需求之一,https://pub.dartlang.org/flutter中搜索Banner找到两个开源库,

引入项目后,分别存在一些问题,其中banner库,没有提供页码指示器。banner_view在手动快速滑动的过程中,会导致bug。

因此决定结合两个项目的优点进行改进,实现效果如下。

主要的布局是由一个Stack包裹着banner内容视图和Indicator指示器视图

其中指示器视图直接使用的banner_view中的代码。banner内容视图部分,使用的是PageView,pageView有个地方比较坑,pageView需要通过PageController控制页面的跳转,但是通过PageController拿到的当前page页码是double类型,并且会丢失精度,需要进行四舍五入,转换成int类型之后,再作为当前页码使用。

源码:

import 'package:flutter/material.dart';

//Created by yangxiaowei at 2018/06/06
//indicator view of banner
class IndicatorWidget extends StatelessWidget {
  final Widget indicatorNormal;
  final Widget indicatorSelected;
  final double indicatorMargin;
  final int size;
  final int currentIndex;

  IndicatorWidget({
    Key key,
    this.size,
    this.currentIndex,
    this.indicatorNormal,
    this.indicatorSelected,
    this.indicatorMargin = 5.0,
  })  : assert(indicatorMargin != null),
        assert(size != null && size > 0),
        assert(currentIndex != null && currentIndex >= 0),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return this._renderIndicator(context);
  }

  //indicator container
  Widget _renderIndicator(BuildContext context) {
    Widget smallContainer = new Container(
      child: new Row(
        mainAxisSize: MainAxisSize.min,
        children: _renderIndicatorTag(),
      ),
    );

    //default implement
    return new Align(
      alignment: Alignment.bottomCenter,
      child: new Opacity(
        opacity: 0.5,
        child: new Container(
          height: 25,
          padding: new EdgeInsets.symmetric(horizontal: 16.0),
          color: Colors.black45,
          alignment: Alignment.centerRight,
          child: smallContainer,
        ),
      ),
    );
  }

  //generate every indicator item
  List<Widget> _renderIndicatorTag() {
    List<Widget> indicators = [];
    final int len = this.size;
    Widget selected = this.indicatorSelected ?? generateIndicatorItem(normal: false);
    Widget normal = this.indicatorNormal ?? generateIndicatorItem(normal: true);

    for (var index = 0; index < len; index++) {
      indicators.add(index == this.currentIndex ? selected : normal);
      if (index != len - 1) {
        indicators.add(new SizedBox(
          width: this.indicatorMargin,
        ));
      }
    }

    return indicators;
  }

  Widget generateIndicatorItem({bool normal = true, double indicatorSize = 8.0}) {
    return new Container(
      width: indicatorSize,
      height: indicatorSize,
      decoration: new BoxDecoration(
        shape: BoxShape.circle,
        color: normal ? Colors.white : Colors.red,
      ),
    );
  }
}
import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_biobank/widget/IndicatorWidget.dart';

///广告banner
///author: yinbiao
///time:2018-12-5
class BannerView extends StatefulWidget {
  final int delayTime; //间隔时间秒
  final int scrollTime; //滑动耗时毫秒
  final double height; //banner高度
  final List<Widget> data; //banner内容
  int _index = 0; //当前位置

  BannerView({Key key, @required this.data, this.delayTime = 3, this.scrollTime = 200, this.height = 200.0}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return new BannerViewState();
  }
}

class BannerViewState extends State<BannerView> {
  PageController controller = new PageController();
  Timer timer;

  @override
  void initState() {
    super.initState();
    resetTimer();
  }

  ///重置计时器
  void resetTimer() {
    clearTimer();
    timer = new Timer.periodic(new Duration(seconds: widget.delayTime), (Timer timer) {
      if (controller.positions.isNotEmpty) {
        ///这里controller.page会丢失精度,需要四舍五入
        widget._index = controller.page.round() + 1;
        controller.animateToPage(widget._index, duration: new Duration(milliseconds: widget.scrollTime), curve: Curves.linear);
        setState(() {});
      }
    });
  }

  ///清除计时器
  clearTimer() {
    if (timer != null) {
      timer.cancel();
      timer = null;
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Stack(
      children: <Widget>[
        _buildBanner(),
        _renderIndicator(),
      ],
    );
  }

  Widget _buildBanner() {
    return new SizedBox(
      width: MediaQuery.of(context).size.width,
      height: widget.height,
      child: new GestureDetector(
        onTapDown: (details) {
          clearTimer();
        },
        onTapUp: (details) {
          resetTimer();
        },
        onTapCancel: () {
          resetTimer();
        },
        child: new PageView.builder(
          controller: controller,
          physics: const PageScrollPhysics(parent: const ClampingScrollPhysics()),
          itemBuilder: (BuildContext context, int index) {
            return widget.data[index % widget.data.length];
          },
          itemCount: 0x7fffffff,
          onPageChanged: (index) {
            setState(() {
              widget._index = index;
            });
          },
        ),
      ),
    );
  }

  /// indicator widget
  Widget _renderIndicator() {
    return new IndicatorWidget(
      size: widget.data.length,
      currentIndex: widget._index % widget.data.length,
    );
  }

  @override
  void dispose() {
    clearTimer();
    super.dispose();
  }
}

使用:

  Widget buildBanner() {
    return new Container(
        alignment: Alignment.center,
        height: 200.0,
        child: new BannerView(
          data: <Widget>[
            buildImage("images/bg_login.png"),
            buildImage("images/banner2.png"),
            buildImage("images/banner3.png"),
            buildImage("images/banner4.png"),
          ],
        ));
  }

参考:

https://github.com/zhangruiyu/BannerView

https://github.com/yangxiaoweihn/BannerView

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

flutter自定义广告Banner 的相关文章

  • 无法获取项目的未知属性“assembleRelease”

    将 Android Studio 更新到版本 2 2 并将 gradle 插件更新到 2 2 0 后 出现以下错误 错误 32 1 评估项目 jobdispatcher 时出现问题 无法获取 org gradle api Project 类
  • 如何通过代码检测Android上的表情符号支持

    通过代码 我可以制作一个按钮 将这 3 个表情符号插入到文本中 不过 在许多手机上 当用户单击按钮时 问题是 显示为 X X X 或者更糟糕的是 它只显示三个空白空间 我想在无法正确显示表情符号的 Android 设备上禁用并隐藏我自己的内
  • 需要对某些片段禁用 CollapsingToolbarLayout 的展开

    我有一个AppCompatActivity控制替换许多片段 这是我的布局 活动 main xml
  • 如何使用具有三种布局的视图翻转器?

    我目前正在使用ViewFlipper我的主要活动有两种不同的布局 我想使用第三种布局 但我只能找到showNext and showPrevious 命令 有人可以告诉我如何使用来实现第三种布局吗ViewFlipper 为您制作了一个示例
  • 升级到 Proguard 4.8 后无法导出应用程序

    我刚刚将我的 Android SDK ADT 和 Proguard 升级到最新最好的版本 我的项目在调试模式下编译并运行良好 但是当我尝试导出它的签名版本 APK 时 我收到来自导出向导的错误Eclipse 控制台上没有任何错误日志消息 如
  • 与通用地图相比,MapView 的分辨率较差

    我刚刚收到 HTC Desire 进行测试 我注意到 残留在小于整个屏幕的框架中的地图视图不如通用地图应用程序那么清晰 有什么办法解决这个问题吗 您应该使用 API 级别 4 或更高级别编译应用程序 然后在 AndroidManifest
  • 将项目添加到 android 框架的设置中

    我正在 android 框架中工作 我想向 android 操作系统中的现有设置添加一个项目 您能告诉我如何执行此操作吗 首先阅读有关偏好活动 http developer android com reference android pre
  • 新安装的Eclipse和Android SDK。无法让模拟器工作。挂在时钟屏幕上

    我对开发是全新的 我已经安装了 Eclipse 和 Andoid SDK 但是 我无法让模拟器工作 我已经尝试过示例记事本代码和 Hello Android 教程代码 每次我尝试运行任一应用程序时 它都会挂在时钟屏幕上 屏幕上还显示正在充电
  • 使用 RoboSpice 有没有办法从异常中获取 HTTP 错误代码?

    我正在编写一个使用 RoboSpice 的应用程序 在请求侦听器 onRequestFailure SpiceException arg0 中 有没有办法确定该错误是由于发生 401 HTTP 错误而导致的 我有一个后端服务 当令牌过期时
  • Android Studio APK META-INF/BCKEY.DSA 中复制的重复文件

    我的代码构建得很好 但是当我尝试在调试中运行它时 出现以下错误 Error Execution failed for task app transformResourcesWithMergeJavaResForDebug com andro
  • 在 Android 中使用 AES 加密的最佳实践是什么?

    我为什么问这个问题 我知道人们对 AES 加密存在很多疑问 即使对于 Android 也是如此 如果您在网络上搜索 会发现很多代码片段 但在每个页面上 在每个 Stack Overflow 问题中 我都发现了另一个具有重大差异的实现 所以我
  • 检测设备方向

    我需要检测 Android 设备方向变化 而无需手动处理传感器数据 同时保持活动方向坚持某个方向 onConfigurationChange不会起作用 因为会让我的活动不旋转 通过使用传感器数据来检测方向变化 我认为这是轮子的发明 因为 A
  • Android中如何使用intent加载本地html页面?

    我的 asset 目录中有一个 html 文件 我必须使用 Intent 将其加载为浏览器应用程序 这是我的代码 但它不起作用 startActivity new Intent Intent ACTION VIEW Uri parse fi
  • foo.setVisibility(View.GONE) 和parent.removeView(foo) 之间的区别

    如果 foo 是一个视图 那么有什么区别foo setVisibility View GONE and fooParent removeView foo 我对两个语句之前和之后视图的内存消耗特别感兴趣 可见性设置为 GONE 的视图是否会消
  • 有没有办法创建 PWA(渐进式 Web 应用程序)的 Android 桌面小部件?

    我正在构建一个渐进式 Web 应用程序 有没有办法创建 Android 桌面小部件 None
  • 活动中列表视图中的粘滞行

    我的列表视图中只有一行应该是粘性的 而不是粘性标题中带有字母的部分或部分 我真的很感激任何关于列表视图在活动中粘性一行而不是片段的帮助 我该怎么做 我真的很感谢任何帮助 提前致谢 使用如下代码 class MyAsyncTask exten
  • Android:选择 EditField 上焦点上的所有文本

    我试图让 Android 在获得焦点时选择 EditText 字段中的所有文本 我在布局中使用此属性 在两个字段上 android selectAllOnFocus true 我不确定这是否相关 但为了将光标移动到第一个可编辑字段 前面 还
  • FCM 主题是否适合更多用户?

    我对使用主题消息有点困惑 我的场景是根据通知触发一些作业 请帮助我更多地了解这一点 如果我们正在处理大量用户 则可以使用 FCM 主题向用户发送通知 我们可以只使用数据消息和主题消息吗 使用主题发送的消息是否保证送达 我在 FCM 文档中看
  • Retrofit 2.0:预期为 BEGIN_OBJECT,但在第 1 行第 1 列路径 $ [重复] 处为 STRING

    这个问题在这里已经有答案了 我在邮递员上传递了更新用户请求并获得了成功的响应 参见图片 现在当我尝试使用 Retrofit 2 在我的应用程序中执行相同操作时 出现错误 com google gson JsonSyntaxException
  • Android Webview隐私浏览

    我在我的 Android 应用程序中使用 webview 从多个站点获取一些网页 我对 webview 行为有一些疑问 webview 是否存储历史记录 cookie 表单自动填充信息 如果是的话 我们可以阻止它这样做吗 如果 Webvie

随机推荐

  • pygame小游戏-------FlappyBird像素鸟的实现

    简述 对FlappyBird像素鸟游戏的简单复现 仅两百行左右 工程目录结构为image文件夹和run py文件 pygame模块的下载直接pip install pygame即可 图片下载地址为像素鸟图片 音频文件自己找一个即可 impo
  • 基于JavaWeb的学生信息管理系统

    项目背景 学生信息管理是学校的重要工作之一 传统的学生信息管理由于是手工操作 工作量大且容易出错 随着计算机和网络技术的迅速发展 越来越多的院校都拥有了自己的学生信息管理系统 而采用B S架构的学生信息管理系统进行学生信息的管理则是其趋势
  • 使用ffmpeg打开本地文件

    其中 AVFormatContext 用来存储视音频封装格式 flv mp4 rmvb avi 中包含的所有信息 很多函数都要用到它作为参数 avformat open input 该函数是打开多媒体数据并且获得一些相关的信息 其中填入的
  • Pytorch 多卡并行(1)—— 原理简介和 DDP 并行实践

    近年来 深度学习模型的规模越来越大 需要处理的数据也越来越多 单卡训练的显存空间和计算效率都越来越难以满足需求 因此 多卡并行训练成为了一个必要的解决方案 本文主要介绍使用 Pytorch 的 DistributedDataParallel
  • C语言实训通讯录(静态和动态版本)

    作者 旧梦拾遗186 专栏 C语言编程 小比特成长日记 相关链接 自定义类型下 枚举 联合 C语言 每日励志 改变 永远不嫌晚 无论你是几岁 也无论你目前所处的境况有多糟 只要立定目标 一步一步往前走 人生随时都有翻盘的可能性 目录 一 前
  • CVE-2023-3450:锐捷 RG-BCR860 命令执行漏洞复现

    锐捷 RG BCR860 命令执行漏洞 CVE 2023 3450 复现 0x01 前言 本次测试仅供学习使用 如若非法他用 与本文作者无关 需自行负责 0x02 漏洞描述 Ruijie Networks RG BCR860是中国锐捷网络
  • 统计学习方法——概述

    统计学习方法之概述 1 统计学习的特点 1 统计学习以计算机及网络为平台 是建立在计算机及网络上的 2 统计学习以数据为研究对象 是数据驱动的学科 3 统计学习的目的是对数据进行预测与分析 4 统计学习以方法为中心 统计学习方法构建模型井应
  • windows10企业版开启RDP多用户同时登录

    1 系统属性 开启远程桌面 添加远程桌面登录用户 2 快捷键win R 输入 gpedit msc 打开本地组策略编辑器 选择 管理模板 gt Windows组件 gt 远程桌面服务 gt 远程桌面会话主机 gt 连接 配置 限制连接的数量
  • 夯实网络安全基石,筑牢网络安全防线

    没有网络安全就没有国家安全 这句话我们常常能在各种新闻里看见 安全是发展的前提 发展是安全的保障 共同推进安全和发展 Z强调 要坚持依法治网 依法办网 依法上网 今年的国家网络安全宣传周在9月11日至17日全国范围内开展 今年的网安周以 网
  • 电脑重装系统后需要更新哪些驱动

    在电脑重装系统后 由于系统的重置 您需要重新安装和更新一些关键的驱动程序 以确保硬件设备正常工作和性能最佳化 以下是在电脑重装系统后需要更新的一些常见驱动程序 工具 原料 系统版本 win10系统 品牌型号 戴尔 XPS13 9350 37
  • H5新增标签 css图标库 web 前端 字体 问题

    目录 css图标库 web前端字体 CSS Hint H5新增标签 1
  • OpenCV学习(2)——图像的数据格式BGR

    OpenCV学习 2 图像的BGR格式解读 1 opencv读取的图片数据格式 2 BGR含义 1 opencv读取的图片数据格式 opencv读取的图片数据格式为numpy的nparray格式 一张二维图片是由像素点构成 如下图所示 其中
  • Mysql:增删改查基础语句

    mysql基础入门语句 增 INSERT INTO 表名 字段1 2 3 VALUES 值1 2 3 删 DELETE FROM 表明 WHERE 删除条件 不提供更新条件 则删除所有 改 UPDATE 表名 SET 字段1 新值 字段2
  • JavaScript学习 -- ajax方法的POST请求

    在Web开发中 通过POST请求将数据发送给服务器是一种常见的方式 使用jQuery可以轻松地发送POST请求 这需要使用jQuery的ajax 方法 本文将介绍jQuery如何使用POST请求发送数据 并提供一个实际的例子 使用 ajax
  • rcp命令

    http www cnblogs com peida archive 2013 03 14 2958685 html rcp代表 remote file copy 远程文件拷贝 该命令用于在计算机之间拷贝文件 rcp命令有两种格式 第一种格
  • Py_Finalize引发的异常

    Py Finalize引发如下异常 0x00007FFFE5A28D10 python38 dll 处 位于 MTFform exe 中 引发的异常 0xC0000005 执行位置 0x00007FFFE5A28D10 时发生访问冲突 解决
  • 项目系列之登录管理

    登录管理是现代计算机系统中关键的组成部分之一 那么本篇博客我们来简单了解一下登录的流程与前后端干了啥事 一 登录流程 用户打开登录页面 用户访问应用程序或网站的登录页面 此页面通常包含用户名 邮箱输入字段和密码输入字段 以及登录按钮 用户输
  • 2、模板方法

    文章目录 概念 demo 概念 父类定义抽象 的 template method 并由别的方法调用 子类实现具体的 template method 和观察者类似 回调函数 钩子函数 都是此模式的应用 观察者一般是多个 方法由被观察者调用 模
  • redhat6.4 下安装oracle 11g详细完整的步骤

    一 虚拟机安装操作系统 Redhat 6 4 注意 linux下安装oracle 11 如果是redhat系统 选择redhat6版本的 因为redhat7版本里面少一个安装数据库用到的包compat libstdc 33 没有这个包 安装
  • flutter自定义广告Banner

    Flutter 1 0 is out Tuesday December 4 2018 Banner是手机应用最常见的需求之一 https pub dartlang org flutter中搜索Banner找到两个开源库 引入项目后 分别存在