当前位置:主页 > android教程 > flutter 流式布局

flutter中使用流式布局示例详解

发布:2023-03-12 18:00:01 59


为网友们分享了相关的编程文章,网友郁常红根据主题投稿了本篇教程内容,涉及到flutter、流式布局、flutter、布局、flutter 流式布局相关内容,已被510网友关注,内容中涉及的知识点可以在下方直接下载获取。

flutter 流式布局

简介

我们在开发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 children = const [],
    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 buttonItems = [
    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((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 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组件,如果和动画进行结合使用,可以得到非常完美的效果。

本文的例子:github.com/ddean2009/l…

以上就是flutter中使用流式布局示例详解的详细内容,更多关于flutter 流式布局的资料请关注码农之家其它相关文章!


相关文章

  • flutter material widget组件之信息展示组件使用详解

    发布:2023-03-02

    这篇文章主要为大家详细介绍了flutter material widget组件之信息展示组件的使用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下


  • Flutter异步操作实现流程详解

    发布:2023-03-13

    在Flutter中,借助 FutureBuilder 组件和 StreamBuilder 组件,可以非常方便地完成异步操作,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧


  • Android开发Flutter 桌面应用窗口化实战示例

    发布:2023-03-13

    这篇文章主要为大家介绍了Android开发Flutter 桌面应用窗口化实战示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪


  • Flutter实现矩形取色器的封装

    发布:2023-03-02

    这篇文章主要为大家详细介绍了Flutter实现矩形取色器的封装,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下


  • Flutter StatefulBuilder实现局部刷新实例详解

    发布:2023-03-02

    这篇文章主要为大家介绍了Flutter StatefulBuilder实现局部刷新实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪


  • Android Flutter实现精灵图的使用详解

    发布:2023-03-03

    在游戏开发中,精灵图会将一个人物所有动作放置在一张图片中,通过坐标定位选取其中一张图展示。本文就来教你如何使用精灵图,感兴趣的可以了解一下


  • Android Flutter实现自定义下拉刷新组件

    发布:2023-03-02

    在Flutter开发中官方提供了多平台的下拉刷新组件供开发者使用。本文将改造一下这些组件,实现自定义的下拉刷新组件,感兴趣的可以了解一下


  • Flutter组件实现进度指示器

    发布:2023-03-02

    这篇文章主要为大家详细介绍了Flutter组件实现进度指示器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下


网友讨论