Flex 填充比例

// 横向布局(可以看上一篇)
Row(
children: [
Flexible(
// 第一个占用 1/6
flex: 1,
child: getItem(1),
),
Flexible(
// 第 2 个占用 2/6
flex: 2,
child: getItem(2),
),
Flexible(
// 第 3 个占用 3/6
flex: 3,
child: getItem(3),
),
],
)

getItem

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

看效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
What? 按照常识来讲这不符合预期啊,刚才上面看到 fit 参数默认是 FlexFit.loose 并且这里 getItem 子项的宽高设置成了 60 ,所以会出现上面的现象。

做些修改

这里我们将 getItem 改为 getItem(1, null, 60) 设置为不限制宽度,看看效果

Flexible(
flex: 1,
fit: FlexFit.loose,
child: getItem(1, null, 60),
)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
这下就符合我们的预期了,我们再来做一些调整, getItem 不变,仅把 fit 参数改为 FlexFit.tight 看看效果

Flexible(
flex: 1,
fit: FlexFit.tight,
child: getItem(1),
)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
这里也符合我们的预期,这是为什么呢?

因为 FlexFit.loose 允许子项与最大的可用空间(1/6)一样大,但是可以更小,我们开始设置了子项宽度是 60 ,所以就是 60 了,不设置子项宽度就是按照允许的最大空间来了。 因为 FlexFit.tight 被迫会将子类填充可用空间(1/6),所以设置后即使我们设置了子项宽度也没有作用

小结一下
  • flex 可用空间比例
  • fit 子项可用空间填充方式
  • FlexFit.loose 允许子项 <= 可用空间
  • FlexFit.tight 子项 == 可用空间

Expanded(展开的)

这个 Widget 也是非常常用的,有了前面的理解,现在我们看看他的实现,就秒懂什么意思了,一起来
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
看到他继承自 Flexible 你就差不多懂了吧,然后我们再看看他 fit 设置的 FlexFit.tight (子项 == 可用空间),现在来看看下面的代码,你说效果是什么?

Row(
children: [
Expanded(
flex: 1,
child: getItem(1),
),
Expanded(
flex: 2,
child: getItem(2),
),
Expanded(
flex: 3,
child: getItem(3),
),
],
)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
对了,正如你所料,他和上面我们 Flexible 展示的最后一个示例效果是一样的。

应用场景

先看看下面简单的异常效果
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
实现代码如下

Row(
children: [
getItem(1),
Text(
‘ZeroFlutter 聊 Expanded,ZeroFlutter 聊 ExpandedZeroFlutter 聊 ExpandedZeroFlutter 聊 ExpandedZeroFlutter 聊 ExpandedZeroFlutter 聊 Expanded’)
],
)

一般我们都要考虑适配性,你想要的可能是这样的
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
实现代码如下,我们使用 Expanded 包裹 Text ,然后设置了最多 2 行,超过 … 显示

Row(
children: [
getItem(1),
// 使用 Expanded 包裹 Text
Expanded(
child: Text(
‘ZeroFlutter 聊 Expanded,ZeroFlutter 聊 ExpandedZeroFlutter 聊 ExpandedZeroFlutter 聊 ExpandedZeroFlutter 聊 ExpandedZeroFlutter 聊 Expanded’,
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
)
],
)

Spacer(弹片)

这个 Widget 可能你是第一次听说,但是从此以后你可能就会经常用到他了,非常好用,比如说我们要做到如下效果,你会怎么做?
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

// 你是这样想的吗?
Row(
children: [
getItem(1),
Expanded(child: SizedBox()),
getItem(2),
Expanded(
child: SizedBox(),
flex: 2,
),
getItem(3)
],
)

根据前面学的,你是上面👆🏻这样想的吗?其实我们可以更简单点,像下面👇🏻这样

Row(
children: [
getItem(1),
Spacer(),
getItem(2),
Spacer(flex: 2),
getItem(3)
],
)

走我们看看实现

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
算上注释总共 66 行代码,其实如果官方不提供,我们如果经常用到有这个需求,也可以自己封装一个。
实现和我们想的一样,这里就是使用 Expanded 包裹了一个 SizedBox

这里我们看到继承自了 StatelessWidget 不可变的,Flutter 中封装 Widget 是否可变取决于本身,这里我们 flex 设置了之后就不会变了,如果要变也是外部发生变化致使 Spacer 变化,所以这点理解很重要。

小结一下

可以自己封装一个。
实现和我们想的一样,这里就是使用 Expanded 包裹了一个 SizedBox

这里我们看到继承自了 StatelessWidget 不可变的,Flutter 中封装 Widget 是否可变取决于本身,这里我们 flex 设置了之后就不会变了,如果要变也是外部发生变化致使 Spacer 变化,所以这点理解很重要。

小结一下
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐