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

简介: 我们在开发web应用的时候,有时候为了适应浏览器大小的调整,需要动态对页面的组件进行位置的调整。这时候就会用到flow layout,也就是流式布局。同样的,在flutter中也有流式布局,这个流式布局的名字叫做Flow。事实上,在flutter中,Flow通常是和FlowDelegate一起使用的,FlowDelegate用来设置Flow子组件的大小和位置,通过使用FlowDelegate.paintChildre可以更加高效的进行子widget的重绘操作。今天我们来详细讲解flutter中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

相关文章
|
2月前
|
存储 容器
Flutter 构建自适应布局
Flutter 构建自适应布局
Flutter 构建自适应布局
|
3月前
|
开发框架 数据安全/隐私保护 开发者
Flutter 是一款强大的跨平台移动应用开发框架,本文深入探讨了其布局与样式设计
Flutter 是一款强大的跨平台移动应用开发框架,本文深入探讨了其布局与样式设计,涵盖布局基础、常用组件、样式设计、实战应用、响应式布局及性能优化等方面,助力开发者打造精美用户界面。
70 7
|
3月前
|
缓存 监控 前端开发
优化 Flutter 应用启动速度的策略,涵盖理解启动过程、资源加载优化、减少初始化工作、界面布局优化、异步初始化、预加载关键数据、性能监控与分析等方面
本文探讨了优化 Flutter 应用启动速度的策略,涵盖理解启动过程、资源加载优化、减少初始化工作、界面布局优化、异步初始化、预加载关键数据、性能监控与分析等方面,并通过案例分析展示了具体措施和效果,强调了持续优化的重要性及未来优化方向。
118 10
|
3月前
|
开发者 容器
Flutter&鸿蒙next 布局架构原理详解
本文详细介绍了 Flutter 中的主要布局方式,包括 Row、Column、Stack、Container、ListView 和 GridView 等布局组件的架构原理及使用场景。通过了解这些布局 Widget 的基本概念、关键属性和布局原理,开发者可以更高效地构建复杂的用户界面。此外,文章还提供了布局优化技巧,帮助提升应用性能。
134 4
|
3月前
|
容器
深入理解 Flutter 鸿蒙版的 Stack 布局:适配屏幕与层叠样式布局
Flutter 的 Stack 布局组件允许你将多个子组件层叠在一起,实现复杂的界面效果。本文介绍了 Stack 的基本用法、核心概念(如子组件层叠、Positioned 组件和对齐属性),以及如何使用 MediaQuery 和 LayoutBuilder 实现响应式设计。通过示例展示了照片展示与文字描述、动态调整层叠布局等高级用法,帮助你构建更加精美和实用的 Flutter 应用。
187 2
|
4月前
|
容器
Flutter&鸿蒙next 布局架构原理详解
Flutter&鸿蒙next 布局架构原理详解
|
4月前
|
Android开发 开发者 容器
flutter:&UI布局 (六)
本文档介绍了Flutter中的UI布局方式,包括线性布局(如Column和Row)、非线性布局(如Stack、Flex、Positioned)以及Wrap布局等。通过具体示例代码展示了如何使用这些布局组件来构建灵活多变的用户界面,例如使用Column垂直排列文本、使用Stack叠加组件、以及利用Wrap实现自动换行的按钮布局等。
118 1
|
7月前
|
容器
flutter 布局管理【详解】
flutter 布局管理【详解】
59 3
|
7月前
Flutter-自定义折叠流布局实现
Flutter-自定义折叠流布局实现
149 0
|
9月前
|
编解码 前端开发 开发者
【Flutter前端技术开发专栏】Flutter中的响应式设计与自适应布局
【4月更文挑战第30天】Flutter框架助力移动应用实现响应式设计与自适应布局,通过层次化布局系统和`Widget`树管理,结合`BoxConstraints`定义尺寸范围,实现自适应。利用`MediaQuery`获取设备信息,调整布局以适应不同屏幕。`FractionallySizedBox`按比例设定尺寸,`LayoutBuilder`动态计算布局。借助这些工具,开发者能创建跨屏幕尺寸、方向兼容的应用,提升用户体验。
202 0
【Flutter前端技术开发专栏】Flutter中的响应式设计与自适应布局

热门文章

最新文章

  • 1
    【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 2
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 3
    【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
  • 4
    【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
  • 5
    【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
  • 6
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 7
    零基础构建即时通讯开源项目OpenIM移动端-Flutter篇
  • 8
    flutter3-dart3-dymall原创仿抖音(直播+短视频+聊天)商城app系统模板
  • 9
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 10
    【06】flutter完成注册页面-密码登录-手机短信验证-找回密码相关页面-并且实现静态跳转打包demo做演示-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
  • 1
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    14
  • 2
    零基础构建即时通讯开源项目OpenIM移动端-Flutter篇
    58
  • 3
    flutter3-dart3-dymall原创仿抖音(直播+短视频+聊天)商城app系统模板
    38
  • 4
    【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    141
  • 5
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    37
  • 6
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
    73
  • 7
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    121
  • 8
    【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
    75
  • 9
    flutter开发中Use ‘const’ with the constructor to improve performance. Try adding the ‘const’ keyword to the constructor invocation.报错如何解决-优雅草卓伊凡
    18
  • 10
    【06】flutter完成注册页面-密码登录-手机短信验证-找回密码相关页面-并且实现静态跳转打包demo做演示-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
    27