Flutter控件封装之轮播图Banner

news2024/11/8 14:16:03

Flutter中实现轮播图的方式有很多种,比如使用三方flutter_swiper,card_swiper等等,使用这些三方,可以很快很方便的实现一个轮播图展示,基本上也能满足我们日常的开发需求,如果说,想要一些定制化的操作,那么就不得不去更改源码或者自己自定义一个,自己定义的话,Flutter中提供了原生组件PageView,可以使用它很方便的来实现一个轮播图。

PageView类似于Android中的ViewPager,可以实现页面的横向或者纵向滑动,具体的使用方式可以直接PageView(),或者使用PageView.builder(),这两种方式都可以实现,区别就是前者会把所有页面一次性初始化出来,而后者则不会,为了便于大家了解这个组件,我们会简单的举一个小案例。

按照以往惯例,我们先看下本篇文章的大纲,大概如下:

1、最终的实现效果一览

2、PageView组件的属性和具体使用

3、轮播图封装注意事项

4、案例源码刨析

5、封装后的源码及使用方式

6、总结

一、最终的实现效果一览

利用PageView,封装了一些特定的效果,比如文字指示器,圆角指示器,以及指示器的位置,轮播图片的缩进展示等等,录制了一个Gif效果图,如下:

二、PageView组件的属性和具体使用

毕竟是使用PageView来实现一个轮播图,那么针对这个组件,我们需要简单的做个介绍:

先看一下基本的常见属性:

属性

类型

概述

scrollDirection

Axis

滚动方向,水平或者垂直,默认水平。

水平:Axis.horizontal

垂直:Axis.vertical

controller

PageController

滚动控制器,可以定位页面,获取页面等信息

onPageChanged

ValueChanged<int>

页面发生改变时的回调

physics

ScrollPhysics

滑动效果,不设置,会根据不同平台有不同的滚动效果

NeverScrollableScrollPhysics 设置后,页面就不可滚动

BouncingScrollPhysics 表示滚动到底了会有弹回的效果,就是iOS的默认交互

ClampingScrollPhysics 表示滚动到底了就给一个效果,就是Android的默认交互

FixedExtentScrollPhysics 就是iOS经典选择时间组件UIDatePicker那种交互

pageSnapping

bool

是否是整页滑动,默认为true

在实际的开发中,PageView.builder()方式使用是居多的,也建议大家以这种方式作为使用,很简单,只需要在itemBuilder里返回页面视图即可,代码如下:

PageView.builder(
            itemCount: 6,
            onPageChanged: (position) {
              print("当前索引为:$position");
            },
            itemBuilder: (context, index) {
              return Container(
                  color: Colors.amber,
                  alignment: Alignment.center,
                  child: Text("我是第$index个页面"));
            })

基本效果如下:

三、轮播图封装注意事项

基本掌握了PageView的用法之后,我们就开始着手封装一个轮播图,先分析一下,构成轮播图的几个要素,第一,满足自动轮播的要求,而且可以动态设置轮播时长,第二,要能满足多种指示器要求,而且位置可以动态设置,第三,要满足手动轮播和自动轮播要求,并且要处理好手势和定时直接的冲突,第四,最主要的就是使用起来要简单。

定时器注意事项

简单的确定要素之后,我们就可以动手书写了,自动轮播很简单,我们只需要开启一个定时器即可,但是定时器需要注意开启和暂停,也就是什么时候开始,什么时候暂停,否则很容易造成轮播混乱现象。

轮播图开始,其一,也就是主动设置了自动轮播属性,进入到页面,我们就需要开启定时,如果页面退入后台,再重新回到前台,我们也是需要开启轮播的,其二就是暂停,除了退入后台暂停之外,还有就是手势滑动的时候也需要暂停,否则就会和定时造成冲突。

手势注意事项

关于手势,如果我们直接监听页面组件的手势,发现是和PageView有冲突的,为了解决这个手势问题,我们可以采用原始指针事件Listener来监听手势滑动。

部分代码如下,手指按下后,取消定时,手指抬起后,开启定时,当然了如果只有按下和抬起,那么则是一个点击事件,我们可以把这个事件回调给用户。

Listener(
          onPointerDown: (event) {
            //手指按下,定时取消
            _pauseTimer();
            _isClick = true;
          },
          onPointerMove: (event) {
            _isClick = false;
          },
          onPointerUp: (event) {
            //手指抬起,定时开启
            _startTimer();
            //作为点击事件
            if (_isClick && widget.bannerClick != null) {
              widget.bannerClick!(_currentPage);
            }
          },
          child: PageView.builder()t
)

指示器注意事项

指示器需要注意,如果说自己用,一种指示器无可厚非,如果是给他人用,那么就要丰富多彩,尽量满足多的需求。

四、案例源码刨析

1、创建定时器

定时器使用的是Timer,定义了两个方法,便于开启和暂停,当轮播时间到时,就可以执行页面切换操作,使用PageController的animateToPage来切换。

/*
  * 开启定时
  * */
  void _startTimer() {
    if (!_isRunning) {
      _isRunning = true;
      _timer = Timer.periodic(Duration(seconds: widget.delay!), (timer) {
        _controller.animateToPage(_pagePosition + 1,
            duration: const Duration(milliseconds: 800),
            curve: Curves.easeInOut);
      });
    }
  }

  /*
  * 暂停定时
  * */
  void _pauseTimer() {
    if (_isRunning) {
      _isRunning = false;
      _timer?.cancel(); //取消计时器
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    _timer?.cancel();
    super.dispose();
  }

2、感知生命周期变化

当页面退入后台和回到前台,我们需要做暂停和开启定时,那么就需要针对页面做监听操作,添加监听后,记得当前类with WidgetsBindingObserver。

// 添加监听
    WidgetsBinding.instance.addObserver(this);


  /*
  * 感知生命周期变化
  * */
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.resumed && widget.autoPlay!) {
      _startTimer(); //页面可见,开启定时
    } else if (state == AppLifecycleState.paused && _isRunning) {
      _pauseTimer(); //页面不可见,关闭定时
    }
  }

3、图片圆角

图片的圆角实现就比较多了,比如Container的装饰器,或者使用组件ClipRRect都可以的。

ClipRRect(
         //设置图片圆角
          borderRadius: BorderRadius.circular(widget.radius!),
          child: getBannerImage(imageUrl)))

4、指示器类型和位置

指示器类型,可以根据业务需求,进行专项定制,目前源码中的类型,有以下几种,分别是,圆形,圆角,矩形,文字,其位置,可以放到中间,左右两边以及轮播图的下方。

/*
  * 指示器
  * */
  Widget _buildIndicators(mainAxisAlignment) {
    if (widget.indicatorType == IndicatorType.text) {
      //文字
      return Container(
        alignment: widget.textIndicatorAlignment,
        child: VipText(
          "${_currentPage + 1}/${widget.imageList!.length}",
          style: widget.textIndicatorStyle,
          backgroundColor: widget.textIndicatorBgColor,
          padding: widget.textIndicatorPadding,
          paddingLeft: widget.textIndicatorPaddingLeft,
          paddingTop: widget.textIndicatorPaddingTop,
          paddingRight: widget.textIndicatorPaddingRight,
          paddingBottom: widget.textIndicatorPaddingBottom,
        ),
      );
    }
    return Row(
      mainAxisAlignment: mainAxisAlignment,
      children: List.generate(widget.imageList!.length, (index) {
        return Container(
          width: _currentPage == index
              ? widget.indicatorWidth
              : widget.indicatorUnWidth ?? widget.indicatorWidth,
          height: _currentPage == index
              ? widget.indicatorHeight
              : widget.indicatorUnHeight ?? widget.indicatorHeight,
          margin: EdgeInsets.symmetric(horizontal: widget.indicatorMargin!),
          decoration: BoxDecoration(
            shape: widget.indicatorType == IndicatorType.circle
                ? BoxShape.circle
                : BoxShape.rectangle,
            borderRadius: widget.indicatorType == IndicatorType.rectangle
                ? BorderRadius.all(Radius.circular(widget.indicatorRadius!))
                : null,
            color: _currentPage == index
                ? widget.indicatorSelectColor
                : widget.indicatorUnSelectColor,
          ),
        );
      }),
    );
  }

5、轮播图缩进效果

缩进的话,有两种,一种除了当前图片,左右图片会变小,当滑动到当前图片之后才会放大,一种就是很简单的缩进。

viewportFraction 可以理解为一页内容占据屏幕的比例,铺满就是1,小于1就是不铺满。

 PageController(viewportFraction: widget.viewportFraction!)

如果说,在滑动的时候,想要图片实现放大和缩小动画,那么我们需要执行一个放大和缩小动画Transform.scale。

return Transform.scale(
                    scale: endScale,
                    child: Container(
                        margin: widget.imageMargin != null
                            ? EdgeInsets.all(widget.imageMargin!)
                            : EdgeInsets.only(
                                left: widget.imageMarginLeft!,
                                top: widget.imageMarginTop!,
                                right: widget.imageMarginRight!,
                                bottom: widget.imageMarginBottom!),
                        child: ClipRRect(
                            //设置图片圆角
                            borderRadius: BorderRadius.circular(widget.radius!),
                            child: getBannerImage(imageUrl))))

五、封装后的源码及使用方式

目前源码已经上传至了Github,大家需要的话,可以查看,由于篇幅有限,就不全部粘贴了,地址:

https://github.com/AbnerMing888/flutter_widget/blob/master/lib/ui/widget/vip_banner.dart

可用属性一览

属性

类型

概述

imageList

List<String>

图片地址集合

titleList

List<String>

标题集合

radius

double

图片圆角

height

double

图片高度

delay

int

多少时间轮播一次

autoPlay

bool

是否自动轮播

bannerClick

Function(int)

条目点击事件

showIndicators

bool

是否展示指示器

imageMarginLeft

double

图片距离左边的距离

imageMarginTop

double

图片距离上边的距离

imageMarginRight

double

图片距离右边的距离

imageMarginBottom

double

图片距离下边的距离

imageMargin

double

图片距离左上右下的距离,统一设置

marginLeft

double

轮播图整体距离左边的距离

marginTop

double

轮播图整体距离上边的距离

marginRight

double

轮播图整体距离右边的距离

marginBottom

double

轮播图整体距离下边的距离

margin

double

轮播图整体距离左上右下的距离

indicatorMarginLeft

double

指示器距离左边的距离

indicatorMarginRight

double

指示器距离右边的距离

indicatorMarginBottom

double

指示器距离底部的距离

indicatorSelectColor

Color

指示器选中的颜色

indicatorUnSelectColor

Color

指示器未选中的颜色

indicatorWidth

double

指示器宽

indicatorHeight

double

指示器高

indicatorUnWidth

double

指示器未选中宽

indicatorUnHeight

double

指示器未选中高

indicatorMargin

double

指示器边距

indicatorType

IndicatorType

指示器类型

circle, rectangle, text

indicatorRadius

double

指示器圆角度数

indicatorBannerBottom

bool

指示器位置,是在banner上还是Banner下

indicatorBottomColor

Color

指示器在Banner下的背景,默认是透明

indicatorBottomHeight

double

指示器在Banner下的高度

indicatorBottomMarginRight

double

指示器在Banner下的 距离右边

indicatorBottomMarginLeft

double

指示器在Banner下的 距离左边

indicatorBottomMainAxisAlignment

MainAxisAlignment

指示器在Banner下的位置

左,中,右

viewportFraction

double

banner缩进

textIndicatorAlignment

Alignment

文字的位置

textIndicatorStyle

TextStyle

文字样式

textIndicatorBgColor

Color

文字指示器背景

textIndicatorPadding

double

文字指示器内边距

textIndicatorPaddingLeft

double

文字指示器内边距左

textIndicatorPaddingTop

double

文字指示器内边距上

textIndicatorPaddingRight

double

文字指示器内边距右

textIndicatorPaddingBottom

double

文字指示器内边距下

titleBgColor

Color

文字Title背景

titleHeight

double

文字Title高度

titleAlignment

Alignment

文字Title的位置

titleStyle

TextStyle

文字Title样式

titleMarginBottom

double

文字Title距离底部

bannerOtherScale

double

除中间外的其他图片缩放比例

placeholderImage

String

Banner 占位图

errorImage

String

Banner 错误图

imageBoxFit

BoxFit

图片伸缩模式

使用方式

普通加载

VipBanner(
          imageList: const [
            "https://www.vipandroid.cn/ming/image/gan.png",
            "https://www.vipandroid.cn/ming/image/zao.png"
          ],
          bannerClick: (position) {
            //条目点击
            Toast.toast(context, msg: position.toString());
          })

文字指示器

VipBanner(
          imageList: const [
            "https://www.vipandroid.cn/ming/image/gan.png",
            "https://www.vipandroid.cn/ming/image/zao.png"
          ],
          indicatorType: IndicatorType.text,
          bannerClick: (position) {
            Toast.toast(context, msg: position.toString());
          })

圆角指示器

VipBanner(
          imageList: const [
            "https://www.vipandroid.cn/ming/image/gan.png",
            "https://www.vipandroid.cn/ming/image/zao.png"
          ],
          indicatorType: IndicatorType.rectangle,
          indicatorRadius: 5,
          indicatorWidth: 20,
          indicatorHeight: 5,
          bannerClick: (position) {
            Toast.toast(context, msg: position.toString());
          })

使用方式呢,有很多的类型,就不一一举例了,大家可以看源码中的页面,地址是:

https://github.com/AbnerMing888/flutter_widget/blob/master/lib/ui/page/view/banner/banner_page.dart

六、总结

在封装的时候,务必要确定的有以下几个要素,一是定时轮播,二是手势和定时冲突解决,三是无限轮播,四是指示器的设置,五是图片轮播的效果,搞定这些潜在的要素,一个简简单单的轮播图封装起来并不难。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/636040.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CloudFlare系列--使用第三方来自定义CDN的IP(笨牛简洁版)

原文网址&#xff1a;CloudFlare系列--使用第三方来自定义CDN的IP(笨牛简洁版)_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍CloudFlare的CDN如何自定义第三方IP。 概述 CloudFlare官网接入域名的方式只能是 NS 接入&#xff0c;这样默认DNS服务器只能改为CloudFlare的D…

第3章 需求分析

第3章 需求分析 3.1 需求分析任务 3.1.1 确定对系统的综合要求 1. 功能需求 通过需求分析应该划分出必须完成的所有功能。 2. 性能需求 性能需求指定系统必须满足的定时约束或容量约束 3. 可靠性和可用性需求 可靠性需求定量地指定系统的可靠性 可用性与可靠性密切相关&…

北京某金融公司面试题,精选10道讲解!

你好&#xff0c;我是田哥 面试造火箭工作拧螺丝&#xff0c;最近一位朋友在面试中被问到各种各样的分布式微服务的面试题&#xff0c;也回答上来了。可是&#xff0c;等正式入职后&#xff0c;发现这家公司居然全部是使用单体项目&#xff0c;完全没有分布式微服务的东东&…

个人PC机使用网线与树莓派进行连接

目录 0. 前言1. 查看网络状况2. 设置网络共享3. 获取树莓派的IP 0. 前言 你需要准备一个树莓派4B&#xff0c;自己的电脑&#xff0c;以及一根超五类网线 操作系统&#xff1a;Windows10 专业版、Raspbian OS 开发环境&#xff1a;树莓派4B 1. 查看网络状况 windows控制台…

今年程序员去大厂面试的必备条件:985或211计算机专业,上家公司是大厂,毕业3年且30岁以下,之前产品qps在一万以上!...

什么样的程序员能拿到大厂的面试入场券&#xff1f; 一位网友总结&#xff0c;今年程序员想约到一二三线公司面试需要同时满足以下条件&#xff0c;缺一不可&#xff1a; 1.985或者211硕士&#xff0c;计算机专业&#xff1b; 2.上家公司是大厂&#xff1b; 3.毕业3年以上且年龄…

chatgpt赋能python:Python中的变量定义

Python中的变量定义 在Python中&#xff0c;变量是一种用来存储数据的容器。它们允许程序员为数据分配一个名称&#xff0c;并将该名称与特定的值关联起来。Python语言的灵活性和易用性使得变量定义变得极为简单。 定义变量的基本语法 在Python中&#xff0c;定义变量的语法…

pikachu靶场漏洞演练(更新中)

文章目录 一、XSS(Cross-Site Scripting)1.XSS概述2.漏洞危害3.常用payloadb.反射型XSS&#xff08;post&#xff09;c.存储型XSSd.DOM型XSSe.DOM型XSS-X 一、XSS(Cross-Site Scripting) 1.XSS概述 XSS中文叫做跨站脚本攻击&#xff08;Cross-site scripting&#xff09;&…

BitSet—位图

BitSet &#x1f50e;概念&#x1f50e;位图的模拟实现set()get()reSet()getUsedSize()完整代码 &#x1f50e;利用位图进行排序&#x1f50e;结尾 &#x1f50e;概念 位图 用某一位表示存储的状态 位图的适用场景 海量数据数据为自然数(≥ 0)数据不重复 举个栗子&#x1f3…

内网隧道代理技术(二)之LCX端口转发

LCX端口转发 LCX介绍 LCX是一款端口转发工具&#xff0c;分为Windows版和Linux版&#xff0c;Linux版本为PortMap。LCX有端口映射和端口转发两大功能&#xff0c;例如当目标的3389端口只对内开放而不对外开放时&#xff0c;可以使用端口映射将3389端口映射到目标的其他端口使…

计算两个向量的外积numpy.outer()

【小白从小学Python、C、Java】 【等级考试500强双证书考研】 【Python-数据分析】 计算两个向量的外积 numpy.outer() 以下说法正确的是&#xff1a; import numpy as np a np.array([1,2]) print("【显示】a ",a) b np.array([3,4,5]) print("【显示】b &q…

SpringBoot进阶-SpringBoot如何实现配置文件脱敏

目录 参考一、概述二、实现1、引入pom2、在配置文件中添加密钥3、生成加密之后的数据4、将加密之后的数据添加到配置文件中 三、踩坑Encryption raised an exception. A possible cause is you are using strong encryption algorithms and you have not installed the Java Cr…

python系列27:jupyter转web app的工具Mercury

1. 简介 官网&#xff1a;https://runmercury.com/ Mercury可以将 Jupyter Notebook 呈现为 Web 应用程序。类似的package还有streamlit和voila 使用import mercury as mr进行安装。Mercury的页面分为左边的输入部分&#xff0c;和右边的输出部分&#xff0c;下面是极简例子&a…

C++函数重载学习

C 允许多个函数拥有相同的名字&#xff0c;只要它们的参数列表不同就可以&#xff0c;这就是函数的重载&#xff08;Function Overloading&#xff09;。 一个基本的例子&#xff1b; #include<iostream> using namespace std;void print(int i) {cout<<"a …

远程控制之原理和实践

按理来说&#xff0c;本人不该发表此类专业文章&#xff0c;鄙人零星碎片化的开发经历&#xff0c;让本人斗胆向诸位网友&#xff0c;在远控方面做一点演示说明&#xff0c;谈论一点自己的认识。 程序工程代码地址&#xff1a;点击此处下载。 程序分为两个部分&#xff0c;控…

OpenCV 项目开发实战--对图像中的斑点进行检测(Python、C++代码实现)

什么是斑点? Blob 是图像中一组连接的像素,它们共享一些共同的属性(例如,灰度值)。在上图中,暗连接区域是斑点,斑点检测旨在识别和标记这些区域。 文末附相关测试代码的下载链接 SimpleBlobDetector 示例 OpenCV 提供了一种基于不同特征检测和过滤斑点的便捷方法。让…

计算机组成原理笔记(王道考研)(持续更新)

文章目录 前言概论计算机的发展计算机系统计算机硬件组成各个硬件的工作原理计算机系统的层次结构计算机系统结构、组成、实现 计算机性能指标储存器CPU整体指标Amdahl定律与加速比 前言 本文是对王道计算机考研《计算机组成原理》课程的总结&#xff0c;主讲咸鱼学长讲的确实…

那些曾经考过的turtle绘图题(1~5)

【编程实现绘图 -1】 使用使用turtle库的函数,绘制三个彩色的圆,圆的颜色按顺序如图,圆的半径从里至外分别是20,50, 100,效果如图所示 # 样例代码 from turtle import * # 导入turtle库 list_r = [20, 50, 100] # 定义半径列表 list_color = ["red", "…

chatgpt赋能python:在画布中间画图的Python技巧

在画布中间画图的Python技巧 在Python中&#xff0c;绘图是数据可视化和图形表示的一种重要方式。然而&#xff0c;在绘制图表时&#xff0c;我们需要让图表的中心点位于画布的正中心&#xff0c;而不是依靠手动计算像素值来实现。这不仅让图表更易读&#xff0c;还提高了可视…

chatgpt赋能python:Python中如何处理多个输入

Python中如何处理多个输入 在编写Python程序时&#xff0c;我们经常需要从用户那里获取多个输入来执行某些操作。本文将介绍Python中的各种方法来处理多个输入。 从终端获取多个输入 Python中最简单的方式是从终端获取多个输入。下面是一个基本的例子&#xff1a; input_st…

chatgpt赋能python:Python中的函数

Python中的函数 Python是一种高级语言&#xff0c;可用于各种应用程序&#xff0c;从Web开发到科学计算。Python中的函数是重要的编程概念之一&#xff0c;它允许开发人员将一段代码重复使用&#xff0c;并可以按照需要调用它们。 函数是什么&#xff1f; 函数是一种拥有参数…