flutter中使用流式布局示例详解
作者:程序那些事 发布时间:2023-08-24 23:49:06
简介
我们在开发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的值。
运行之后的效果如下:
初始状态下,所有的组件都是在一起的。
当我们点击上面的图标的时候,我们可以得到下面的界面:
图标在动画中展开了。
来源:https://juejin.cn/post/7146098348250890253


猜你喜欢
- 目录简介springfox大致原理:SpringBoot整合Swagger2引入依赖编写配置类配置SwaggerSwagger2常用注解使用
- 使用idea创建javaweb项目idea还是写框架项目比较爽,原生的javaweb项目不是特别方便,这篇文章就是记录一下创建的过程图较多注
- 效果图接下来就是一波贴代码的过程自定义Dialogpublic class SinaSendView extends Dialog { &n
- 在 Windows 有一些字符是不能作为文件名,尝试重命名一个文件,输入/ 就可以看到windows 提示的不能作为文件名的字符那么具体是包
- 前言制作无边框窗口时,系统自带阴影会消失,这时就需要我自己给窗口添加阴影以防止窗口融入背景。添加阴影的方法很简单,直接用effect就可以了
- 写在前面本文讲解的是如何使用Spring动态配置文件,实现不同环境不同配置,灵活切换配置文件;以及讲述了如何使用 Maven 打包,然后上传
- 1. InputStream -> byte[]引入 apache.commons.is 包import org.apache.com
- 最新的IDEA激活方式使用网上传统的那种输入网址的方式激活不了,使用http://idea.lanyus.com/这个网站提供的工具进行1、
- ArrayBlockingQueue介绍ArrayBlockingQueue是数组实现的线程安全的有界的阻塞队列。线程安全是指,ArrayB
- 本人一直使用的是Eclipse作为开发工具的,不过现在IDEA非常的受推崇,所以决定上手试一试。网上有很多旗舰版的文章,我没有仔细看,我这次
- 本文实例为大家分享了Java流布局图形界面编写代码,供大家参考,具体内容如下package jisuanqi;import java.awt
- 一、什么是 LRU 算法就是一种缓存淘汰策略。计算机的缓存容量有限,如果缓存满了就要删除一些内容,给新内容腾位置。但问题是,删除哪些内容呢?
- 在项目开发上,hibernate提供的经验简化了不少工作量和兼容性,但这些绝对需要有经验后才能明白,对于新手来说使用起来很困难。hibern
- OSS不支持通过一个网络地址来上传图片,所以若想将网络上的图片上传到OSS上需要走点弯路。1、通过链接将图片下载到本地的一个文件夹下面2、用
- 本文实例为大家分享了Java使用MulticastSocket实现群聊应用程序的具体代码,供大家参考,具体内容如下在这篇文章中,讨论了一个使
- 1.关于7z首先在这里先介绍一下7z压缩软件,7z是一种主流的 压缩格式,它拥有极高的压缩比。在计算机科学中,7z是一种可以使用多种压缩算法
- 一般认为:foreach (object obj in checkedListBox1.SelectedItems)即可遍历选中的值。其实这
- 本文的目的是要实现左右滑动的指引效果。那么什么是指引效果呢?现在的应用为了有更好的用户体验,一般会在应用开始显示一些指引帮助页面,使用户能更
- 大家好,记得上次我带着大家一起实现了一个类似与淘宝客户端中带有的图片滚动播放器的效果,但是在做完了之后,发现忘了加入图片自动播放的功能(或许
- 引言一个复杂的分布式系统,用户发起一个请求,这个请求可能调用几十到几百个服务,经过很多业务层,而每个业务又是多个机器集群,一个请求具体被随机