flutter系列之:在flutter中使用流式布局

news2024/11/24 20:41:51

文章目录

  • 简介
  • Flow和FlowDelegate
  • Flow的应用
  • 总结

简介

我们在开发web应用的时候,有时候为了适应浏览器大小的调整,需要动态对页面的组件进行位置的调整。这时候就会用到flow layout,也就是流式布局。

同样的,在flutter中也有流式布局,这个流式布局的名字叫做Flow。事实上,在flutter中,Flow通常是和FlowDelegate一起使用的,FlowDelegate用来设置Flow子组件的大小和位置,通过使用FlowDelegate.paintChildre可以更加高效的进行子widget的重绘操作。今天我们来详细讲解flutter中flow的使用。

Flow和FlowDelegate

先来看下Flow的定义:

class Flow extends MultiChildRenderObjectWidget

Flow继承自MultiChildRenderObjectWidget,说它里面可以包含多个子widget。

再来看下它的构造函数:

  Flow({
    Key? key,
    required this.delegate,
    List<Widget> children = const <Widget>[],
    this.clipBehavior = Clip.hardEdge,
  }) : assert(delegate != null),
       assert(clipBehavior != null),
       super(key: key, children: RepaintBoundary.wrapAll(children));

可以看到Flow中主要有三个属性,分别是delegate,children和clipBehavior。

children很好理解了,它就是Flow中的子元素。

clipBehavior是一个Clip类型的变量,表示的是如何对widget进行裁剪。这里的默认值是none。

最后一个非常重要的属性就是FlowDelegate,FlowDelegate主要用来控制Flow中子widget的位置变换。所以,当我们在Flow中定义好子widget之后,剩下的就是定义FlowDelegate来控制如何展示这些子widget。

FlowDelegate是一个抽象类,所以我们在使用的时候,需要继承它。

FlowDelegate有几个非常重要的方法:

 Size getSize(BoxConstraints constraints) => constraints.biggest;

这个方法用来定义Flow的size,对于Flow来说,它的size是和子widget的size是独立的,Flow的大小通过getSize方法来定义。

接下来是getConstraintsForChild方法:

  BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) => constraints;

getConstraintsForChild用来控制子widget的Constraints。

paintChildren用来控制如何绘制子widget,也是我们必须要实现的方法:

  void paintChildren(FlowPaintingContext context);

FlowDelegate还有两个方法,分别用来判断是否需要Relayout和Repaint,这两个方法的参数都是FlowDelegate:

bool shouldRelayout(covariant FlowDelegate oldDelegate) => false;
bool shouldRepaint(covariant FlowDelegate oldDelegate);

Flow的应用

有了上面的介绍,我们基本上已经了解如何构建Flow了,接下来我们通过一个具体的例子来加深对Flow的理解。

在本例中,我们主要是使用Flow来排列几个图标。

首先我们定义一个图标的数组:

  final List<IconData> buttonItems = <IconData>[
    Icons.home,
    Icons.ac_unit,
    Icons.adb,
    Icons.airplanemode_active,
    Icons.account_box_rounded,
  ];

然后通过每个图标对应的IconData来构建一个IconButton的widget:

  Widget flowButtonItem(IconData icon) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 10.0),
      child: IconButton(
        icon: Icon(icon,
          size: 50,
            color: Colors.blue
        ),
          onPressed: () {
            buttonAnimation.status == AnimationStatus.completed
                ? buttonAnimation.reverse()
                : buttonAnimation.forward();
          },

      )
    );
  }

这里我们使用的是IconButton,为了在不同IconButton之间留一些空间,我们将IconButton封装在Padding中。

在onPressed方法中,我们希望能够处理一些动画效果。这里的buttonAnimation是一个AnimationController对象:

AnimationController  buttonAnimation = AnimationController(
      duration: const Duration(milliseconds: 250),
      vsync: this,
    );

有了flowButtonItem之后,我们就可以构建Flow了:

  Widget build(BuildContext context) {
    return Flow(
      delegate: FlowButtonDelegate(buttonAnimation: buttonAnimation),
      children:
      buttonItems.map<Widget>((IconData icon) => flowButtonItem(icon)).toList(),
    );
  }

Flow的child就是我们刚刚创建的flowButtonItem,FlowButtonDelegate是我们需要新建的类,因为之前在构建flowButtonItem的时候,我们希望进行一些动画的绘制,而FlowDelegate又是真正用来控制子Widget绘制的类,所以我们需要将buttonAnimation作为参数传递给FlowButtonDelegate。

下面是FlowButtonDelegate的定义:

class FlowButtonDelegate extends FlowDelegate {
  FlowButtonDelegate({required this.buttonAnimation})
      : super(repaint: buttonAnimation);

  final Animation<double> buttonAnimation;

  @override
  bool shouldRepaint(FlowButtonDelegate oldDelegate) {
    return buttonAnimation != oldDelegate.buttonAnimation;
  }

  @override
  void paintChildren(FlowPaintingContext context) {
    double dy = 0.0;
    for (int i = 0; i < context.childCount; ++i) {
      dy = context.getChildSize(i)!.height * i;
      context.paintChild(
        i,
        transform: Matrix4.translationValues(
          0,
          dy * buttonAnimation.value,
          0,
        ),
      );
    }
  }

FlowButtonDelegate继承自FlowDelegate,并且传入了buttonAnimation对象。

这里我们根据buttonAnimation是否发生变化来决定是否进行Repaint。

如果需要进行Repaint,那么就要调用paintChildren的方法。

在paintChildren中,我们根据child自身的height和buttonAnimation的值来进行动画的绘制。

那么buttonAnimation的值是如何变化的呢?这就要回顾之前我们创建flowButtonItems的onPress方法了。

在onPress方法中,我们调用了buttonAnimation.reverse或者buttonAnimation.forward这两个方法来修改buttonAnimation的值。

运行之后的效果如下:

初始状态下,所有的组件都是在一起的。

当我们点击上面的图标的时候,我们可以得到下面的界面:

图标在动画中展开了。

总结

Flow是一种比较复杂的layout组件,如果和动画进行结合使用,可以得到非常完美的效果。

本文的例子:https://github.com/ddean2009/learn-flutter.git

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

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

相关文章

真题集P93---2017年计专真题

真题集P93---2017年计专真题六思路&#xff1a;模拟代码七思路一&#xff1a;哈希表法二&#xff1a;排序法 (利用排序去重)三&#xff1a;拓展代码&#xff08;仅思路一&#xff09;六 思路&#xff1a;模拟 1、接口介绍 int turnNum(int num[], int nums)&#xff1a;拿来一…

数据库约束

约束概述 为什么需要约束 数据完整性&#xff08;Data Integrity&#xff09;是指数据的精准性&#xff08;Accuracy&#xff09;和可靠性&#xff08;Reliability&#xff09;。它是防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或错误信息而…

种草软文怎么写?分享一些超实用的种草软文写作技巧。

一提起“种草”这个词语&#xff0c;想必很多小伙伴都不陌生&#xff0c;我们都有“被种草”的经历&#xff0c;指的就是把一件商品推荐给大家&#xff0c;分享给需要的人&#xff0c;然后促成销售转化的过程。 在一些主流的内容平台&#xff0c;比如知乎、小红书、得物、公众…

Android 9.0 MediaPlayer播放流程分析

1.MediaPlayer初始化流程 EventHandler是后面处理数据回调的handler. 在AudioFlinger.cpp中获取nextUniqueId&#xff1a; audio_unique_id_t AudioFlinger::nextUniqueId(audio_unique_id_use_t use) {// This is the internal API, so it is OK to assert on bad parameter.…

18-1、k8s 对外服务之ingress

一、什么是ingress 原来的项目是部署在一台电脑上的&#xff0c;这样爬取速度虽然很快&#xff0c;但是我们还能提升&#xff0c;联想到分布式的思想&#xff0c;我们是否可以通过多台电脑进行配合爬取&#xff0c;这样我们的爬取速度就能大幅度提升。 …

【Mysql】数据库的基本操作和表的增删改查

本章内容是,用sql语言实现对数据库的基本操作和表的基本操作 文章目录前言1. 数据库的基本操作1.1 创建数据库1.2 查看数据库1.3 选中数据库1.4 删除数据库2. 数据库基本数据类型3. 表的基本操作3.1 创建表3.2 显示数据库中的表3.3 查看表的构造3.4 删表4. 表的增删改查4.1 增加…

基于PHP+MySQL汽车查询系统的设计与实现

随着时代的发展,汽车已经逐渐成为人们代步的主要工具之一,按时因为工业的发展,汽车的品牌和型号也层出不穷,如此多的汽车信息如何能够让爱车人士更好的 汽车查询系统的主要功能包含&#xff1a;汽车的类别管理、汽车的信息管理、留言管理、用户的管理等。网站分为管理员、会员用…

开放与融合趋势下,工业互联网安全破圈之道

作者 | 伍杏玲 出品 | CSDN 在工业 4.0 和数字经济的发展促进下&#xff0c;工业互联网作为连接工业经济的重要要素&#xff0c;成为推动数字经济发展的重要基础设施。据统计&#xff0c;到 2025 年&#xff0c;全球 IoT 连接设备数量达 519 亿。 然而在 OT 和 IT 融合趋势下…

1721. 交换链表中的节点-仅遍历一次链表-考研满分答案

1721. 交换链表中的节点-仅遍历一次链表 给你链表的头节点 head 和一个整数 k 。 交换 链表正数第 k 个节点和倒数第 k 个节点的值后&#xff0c;返回链表的头节点&#xff08;链表 从 1 开始索引&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k…

第1关:Hbase数据库的安装

在安装HBase之前你需要先安装Hadoop和Zookeeper&#xff0c;如果你还没有安装可以通过这两个实训来学习&#xff1a;Hadoop安装与配置&#xff0c;Zookeeper安装与配置。 本次实训的环境已经默认安装好了Hadoop&#xff0c;接下来我们就开始安装配置HBase吧。 HBase安装 HBas…

浙大MPA常规批复试上岸经验分享

在经历笔试和面试的备考后&#xff0c;去年终于来到了复试环节&#xff0c;好在通过自己的不懈努力和不放松的精神&#xff0c;最终成功上岸&#xff0c;现在把个人的备考经验做整理为大家做个参考&#xff01; 一、复试前准备&#xff1a;在正式复试前建议一定要对浙大MPA项目…

【综合评价分析】topsis评价 原理+完整MATLAB代码+详细注释+操作实列

【综合评价分析】topsis评价 原理完整MATLAB代码详细注释操作实列 文章目录 1、TOPSIS法的原理 2、TOPSIS法案例分析 3.建立模型并求解 3.1数据预处理 3.2代码实现数据预处理 3.3 本案例中数据预处理的运用 4.计算距离和评价指标 4.1 代码 4.2 运行结果 5.总结 1、T…

基于Jsp的OA企业人事管理系统【论文、数据库设计、源码、开题报告】

数据库脚本下载地址&#xff1a; https://download.csdn.net/download/itrjxxs_com/86500769 主要使用技术 SpringspringMVCmybatisjspccsjsMysqlTomcat 功能介绍 部门管理&#xff1a;支持对部门信息&#xff08;部门名称、部门类型、电话、传真、描述、上级部门&#xff…

外卖项目(项目优化1)10---缓存优化

优化前面已经创建好的项目&#xff1a;将一些问题进行优化处理。本节主要解决是下面的问题。 前面的的项目&#xff0c;是将短信验证码等数据缓存到session中&#xff0c;该部分进行优化后&#xff0c;是将数据内容缓存到Redis中。 目录 一、使用git管理代码&#xff08;对ID…

Guava环境设置

Guava本地环境设置 这部分指导如何下载和设置Java在机器上。请按照以下步骤来设置环境。 Java SE免费提供链接&#xff1a;下载Java。所以&#xff0c;根据操作系统下载对应版本。 按照说明下载java和运行.exe 在机器上&#xff0c;并按说明安装Java。一旦机器上安装了Java&…

Leetcode原题电话号码的字母组合的两种解法【BFS-DFS】

来源&#xff1a;LeetCode 第17题【公众号&#xff1a;数据结构和算法】 给定一个仅包含数字2-9的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按任意顺序返回。给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意1不对应任何字母。 示例1&am…

浅析分布式数据库

前言 随着信息技术的迅猛发展&#xff0c;各行各业产生的数据量呈爆炸式增长&#xff0c;传统集中式数据库的局限性在面对大规模数据处理中逐渐显露&#xff0c;从而分布式数据库应运而生。分布式数据库是在集中式数据库的基础上发展起来的&#xff0c;是分布式系统与传统数据…

java刷题day 06

一. 单选题&#xff1a; 解析&#xff1a;最终类也叫密封类&#xff0c;是被final修饰的类&#xff0c;不能被继承 解析&#xff1a; A&#xff1a;6入&#xff0c;5 入&#xff0c;5出&#xff0c;4入&#xff0c;4出&#xff0c;3入&#xff0c;3出&#xff0c;6出&#xff0…

SpringBoot 封装 HBase 操作工具类

最近项目中用到了Hbase相关的操作并封装成工具类&#xff0c;我的Hbase服务器端版本是2.1.0&#xff0c;图示如下&#xff1a; 特此记录便于日后查阅。 一、pom.xml 依赖 <dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-shaded-…

【C++】快速入门list的使用

文章目录一、引入二、构造三、迭代器四、增删查五、其他操作一、引入 list的本质是带头双向循环链表&#xff0c;对于带头双向循环链表我们可是比较熟悉的了。本文只对list的一些常用接口进行说明&#xff0c;对于其他一些接口可自行查看文档。 二、构造 void Test() {list<…