likes
comments
collection
share

Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets

作者站长头像
站长
· 阅读数 26

前言

前面几篇介绍了ListViewGridViewWrapColumnRow 等这些在平面列表布局,今天我们要聊的是 Stack ,可以叫他栈布局也叫层级布局,主要来显示平面重叠布局,可以更加灵活的控制子项的位置。

简单使用

这里我们添加 3 个大小不同子项,看看他们是怎么排列的。

Stack(
  children: [
    getItem(3, width: 120, height: 120, color: Colors.purple),
    getItem(2, width: 80, height: 80, color: Colors.blue),
    getItem(1),
  ],
)

getItem

这里除 index 外,其他参数使用了选择参数


/// 获取子项目(这里使用了选择参数)
Widget getItem(int index,
               {double? width = 60, double? height = 60, Color color = Colors.orange}) {
  return Container(
    // 宽高设置 60
    width: width,
    height: height,
    // 设置背景色
    color: color,
    // 设置间隙
    margin: EdgeInsets.all(2),
    // 设置子项居中
    alignment: Alignment.center,
    // 设置子项
    child: Text('$index'),
  );
}

看效果

Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets

alignment (对齐方式)

如果你看看源码可以看到这个参数的默认值是 AlignmentDirectional.topStart ,但是这里我们依然可以使用我们熟悉的 Alignment.topLeft 来进行参数设置,这是为什么呢?我们看看来看看 AlignmentDirectional 源码吧,Alignment 源码在前面的章节我们看过了

Stack(
  // 居中对齐
  alignment: Alignment.topLeft,
  children: [
    getItem(3, width: 120, height: 120, color: Colors.purple),
    getItem(2, width: 80, height: 80, color: Colors.blue),
    getItem(1),
  ],
)

Alignment 和 AlignmentDirectional 源码

// Alignment
class Alignment extends AlignmentGeometry {
  /// Creates an alignment.
  ///
  /// The [x] and [y] arguments must not be null.
  const Alignment(this.x, this.y)
    : assert(x != null),
      assert(y != null);
  static const Alignment topLeft = Alignment(-1.0, -1.0);
  static const Alignment center = Alignment(0.0, 0.0);
  ...
}

// AlignmentDirectional
class AlignmentDirectional extends AlignmentGeometry {
  const AlignmentDirectional(this.start, this.y)
    : assert(start != null),
      assert(y != null);
  static const AlignmentDirectional topStart = AlignmentDirectional(-1.0, -1.0);
  // 考虑使用 Alignment.center 代替
  static const AlignmentDirectional center = AlignmentDirectional(0.0, 0.0);
 	...
}

上面我们贴出了核心源码,可以看出他俩都是继承自 AlignmentGeometry ,然后实现也是差不多,而且源码中的注释也是推荐我们使用 Alignment 代替

各种对齐方式效果

这里我们就使用 Alignment 了

Alignment.topLeftAlignment.topCenterAlignment.topRight
Flutter 中 Stack 的使用详解(内含对比图) | Flutter WidgetsFlutter 中 Stack 的使用详解(内含对比图) | Flutter WidgetsFlutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets
Alignment.centerLeftAlignment.centerAlignment.centerRight
Flutter 中 Stack 的使用详解(内含对比图) | Flutter WidgetsFlutter 中 Stack 的使用详解(内含对比图) | Flutter WidgetsFlutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets
Alignment.bottomLeftAlignment.bottomCenterAlignment.bottomRight
Flutter 中 Stack 的使用详解(内含对比图) | Flutter WidgetsFlutter 中 Stack 的使用详解(内含对比图) | Flutter WidgetsFlutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets

学点技巧

当我们输入 **Alignment.bottomRight** 这类参数时,因为单次比较长如果全部输入就太麻烦了,我们可以输入部分前缀+常量的首字母,如下

  • Alignment.bottomRight => alibr

Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets

  • Alignment.center => alic

Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets

阅读我得文章你会发现,不光有源码分析、结构化梳理还有各种实用的技巧,记得关注我哦

fit(填充方式)

为了展示效果,我们先添加一个背景 BgContainer (之前的篇章封装的通用组件)

BgContainer(
  child: Stack(
    // 居中
    alignment: Alignment.center,
    // 设置默认值 loose
    fit: StackFit.loose,
    children: [
      getItem(3, width: 120, height: 120, color: Colors.purple),
      getItem(2, width: 80, height: 80, color: Colors.blue),
      getItem(1),
    ],
  ),
)

Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets

StackFit.loose (疏松的) - 默认

这里为了显示效果我们使用了 DevTools 中的 Widget Inspector 来调试布局,之后可能会聊 Flutter DevTools 的使用技巧(这里不做承诺,还是可能回聊)Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets通过上图可以看到此时 Stack 的大小取决于子项中最大的(也就是紫色 120 宽高的子项)

StackFit.expand(展开的)

Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets这里似乎不是很符合预期,理论上不应该是扩展 Stack 到最大即可吗?

目前我们的子项都是没有设置定位的,所以此时所有的子类约束都会扩展到与Stack 最大值一致

添加定位

我们此时做一点点改变看看效果,先看代码

BgContainer(
  child: Stack(
    alignment: Alignment.center,
    fit: StackFit.expand,
    children: [
      getItem(3, width: 120, height: 120, color: Colors.purple),
      getItem(2, width: 80, height: 80, color: Colors.blue),
      // 这添加了定位
      Positioned(
        // 距左边 10 
        left: 10,
        // 距上边 10 
        top: 10,
        child: getItem(1),
      ),
    ],
  ),
)

Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets此时看到效果了,1 黄色 子项遵循了自己的约束,因为他添加了定位,其他 2、3 因为没有添加定位所以和 Stack 一样大,约束被传递。

这里我们暂时不讲定位的使用,下篇我们系统的聊

StackFit.passthrough(直穿的)

我们先看看效果Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets这里似乎和 loose 没有啥区别啊?我们可以看看源码后改变成以下的示例代码再看看

BgContainer(
  // 添加了一个横向布局
  child: Row(
    children: [
      // 添加了展开组件,前面讲过可以去专栏看看
      Expanded(
        child: Stack(
          alignment: Alignment.center,
          // 设置填充方式为 passthrough
          fit: StackFit.passthrough,
          children: [
            getItem(3, width: 120, height: 120, color: Colors.purple),
            getItem(2, width: 80, height: 80, color: Colors.blue),
            Positioned(
              left: 10,
              top: 10,
              child: getItem(1),
            ),
          ],
        ),
      )
    ],
  ),
),
)

Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets这里我们看到与 expand 还有些不同,这里我们只展开了宽度,高度还是子项的高度。因为这里 Stack 的宽度约束是展开的屏幕宽度,直接传递给了没有添加定位的子组件,所以看到 2、3 子组件跟着变了,而 1 子组件的大小没有发生变化。

如果是 loose 会怎样?

Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets

对于非定位组件会继续保持对齐方式和子项的约束

小总结

Flutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets

clipBehavior(剪裁行为)

当我们设置的子项定位后大小超过了 Stack 布局的时候,我们期望怎样剪裁渲染呢?是剪裁还是显示,是带抗锯齿还是不带呢?

BgContainer(
  child: Stack(
    alignment: Alignment.center,
    fit: StackFit.passthrough,
    // 设置剪裁行为默认 hardEdge
    clipBehavior: Clip.hardEdge,
    children: [
      getItem(3, width: 120, height: 120, color: Colors.purple),
      getItem(2, width: 80, height: 80, color: Colors.blue),
      // 这里设置定位左上角 -20
      Positioned(
        left: -20,
        top: -20,
        child: getItem(1),
      ),
    ],
  ),
)

看效果

Clip.none(不剪裁)Clip.hardEdgeantiAlias、antiAliasWithSaveLayer
Flutter 中 Stack 的使用详解(内含对比图) | Flutter WidgetsFlutter 中 Stack 的使用详解(内含对比图) | Flutter WidgetsFlutter 中 Stack 的使用详解(内含对比图) | Flutter Widgets

一般是默认和不剪裁进行设置,其他的可以回看剪裁篇,介绍了不同。

到这里 Stack 核心内容就聊完了,下篇我们结合聊定位组件「Positioned、Align」聊聊,记得关注我的专栏哦

源码仓库

基于 Flutter 🔥 最新版本

参考链接

关注专栏

  • 此文章已收录到下面👇 的专栏,可以直接关注
  • 更多文章继续阅读|系列文章持续更新

👏 欢迎点赞➕收藏➕关注,有任何问题随时在下面👇评论,我会第一时间回复哦

转载自:https://juejin.cn/post/6972832392792932389
评论
请登录