Flutter Stack 用法小结
记录一下如何使用 Flutter Stack Widget 来将文本跟图片中的某个特定点对齐。
某个产品需求要求显示本月累计签到天数,于是设计给了开发如下一张图。
设计姐姐”好心”地将文案也写好了,只留了个格让开发填,够简单吧。但其实开发很头疼:”累计签到”那一行文案是特殊字体,所以并不能吐槽设计的切图方式完全不合理。但问题是对背景图”填空”容易引起适配问题,稍有不慎就如下图一样没对齐。
接下来看如何在 Flutter 中解决上述对齐问题。涉及到的几个要点:
- 图片缩放 - 我们知道图片适配不同大小屏幕大小
- 了解
Image.fit
属性 - 这个属性控制着图片如何缩放 - 了解
Stack
+Positioned
的基本用法 - 了解
Stack
+Align
的基本用法
图片缩放
我们知道图片适配不同大小屏幕时必然出现不同程度的缩放。Flutter 中使用 Image
控件显示图片,Image.fit
属性则用于控制图片缩放方式。fit
属性为枚举类型 BoxFit
,最常用值的包括如下几种:
fill
- Fill the target box by distorting the source’s aspect ratio.contain
- As large as possible while still containing the source entirely within the target box.cover
- As small as possible while still covering the entire target box.
先来看如何将背景图铺满 Stack
。代码如下:
1 | Stack( |
不同参数时效果分别如下:
Image.asset(width: null, fit: null)
Image.asset(width: double.infinity, fit: null)
Image.asset(width: double.infinity, fit: BoxFit.fill)
Image.asset(width: double.infinity, fit: BoxFit.cover)
就这里的场景而言(图片高度无限制),BoxFit.cover
和 BoxFit.fill
效果无区别。不过 BoxFit.cover
保证图片不会变形,是个更好的选择。
控件定位
Stack 类用于对若干个控件以层叠方式布局。例如:
1 | Stack( |
Stack
控件的子节点要么是 positioned
(Positioned
或 Align
控件) 要么是 non-positioned
。Stack
控件的大小刚好包含所有的 non-positioned
子控件(这些控件默认位于 Stack 的左上角)。而 positioned
子节点的位置,则由其 top, right, bottom, left 属性来决定。
Positioned
和 Align
控件都能用于 Stack
控件定位和对齐。Positioned
以 top, right, bottom, left 属性来定位,这些属性分别用于指定控件到 Stack 各边框的距离;Align
以 Alignment(x, y)
属性来定位,这些属性分别用于指定控件水平方向和垂直方向的距离范围。
Alignment
的 x, y 属性规定如下:
Alignment(0.0, 0.0)
- 表示矩形中点Alignment(-1.0, -1.0)
- 表示矩形左上角Alignment(1.0, 1.0)
- 表示矩形右下角
关于 Stack
有一个小细节要注意。通过如下两个例子说明:
1 | Scaffold( |
这个例子中,Text
按预期居显示:
然而,当 Stack 外面嵌套一个 Column 或 ListView 之后,Align 似乎在垂直方向失去了定位的作用。
1 | Scaffold( |
我们观察 Stack 外面嵌套一个 Column 或 ListView 之后控件树,截图如下:
所以这个现象不难理解:
- Stack 外面无嵌套时,它占满了父控件,所以
Align
生效 - Stack 外面嵌套
Column
或ListView
时,Stack 大小未指定(最终以Text
大小为准),所以Align
从视觉效果上看在垂直方向不起作用。
给 Stack 指定大小就能解决这个问题。这里使用 SizedBox
指定 Stack 高度为 300。
解决方案
方案一
方案一使用 Stack
+ Positioned
定位,代码如下:
1 |
|
注意这里的实现细节,即按图片缩放比 scale 来调整 top 和 right,保证不同大小屏幕上都能完美适配。
方案二
方案二使用 Stack
+ Align
定位,代码如下:
1 | Widget build(BuildContext context) { |
注意这里的实现细节,即为 Stack
添加一个指定大小的 SizeBox
(大小与图片显示的大小相同),保证不同大小屏幕上都能完美适配。
如果不为 Stack
指定大小,则 Align
在垂直方向不生效。如下图: