Flutter 布局(八)- Stack、IndexedStack、GridView详解

this.fit = StackFit.loose,
this.overflow = Overflow.clip,
List children = const [],
})

1.5.1 属性解析

alignment:对齐方式,默认是左上角(topStart)。

textDirection:文本的方向,绝大部分不需要处理。

fit:定义如何设置non-positioned节点尺寸,默认为loose。

其中StackFit有如下几种:

  • loose:子节点宽松的取值,可以从min到max的尺寸;
  • expand:子节点尽可能的占用空间,取max尺寸;
  • passthrough:不改变子节点的约束条件。

overflow:超过的部分是否裁剪掉(clipped)。

1.5.2 源码

Stack的布局代码有些长,在此分段进行讲解。

    1. 如果不包含子节点,则尺寸尽可能大。

if (childCount == 0) {
size = constraints.biggest;
return;
}

  • 2.根据fit属性,设置non-positioned子节点约束条件。

switch (fit) {
case StackFit.loose:
nonPositionedConstraints = constraints.loosen();
break;
case StackFit.expand:
nonPositionedConstraints = new BoxConstraints.tight(constraints.biggest);
break;
case StackFit.passthrough:
nonPositionedConstraints = constraints;
break;
}

  • 3.对non-positioned子节点进行布局。

RenderBox child = firstChild;
while (child != null) {
final StackParentData childParentData = child.parentData;
if (!childParentData.isPositioned) {
hasNonPositionedChildren = true;
child.layout(nonPositionedConstraints, parentUsesSize: true);
final Size childSize = child.size;
width = math.max(width, childSize.width);
height = math.max(height, childSize.height);
}
child = childParentData.nextSibling;
}

  • 4.根据是否包含positioned子节点,对stack进行尺寸调整。

if (hasNonPositionedChildren) {
size = new Size(width, height);
} else {
size = constraints.biggest;
}

  • 5.最后对子节点位置的调整,这个调整过程中,则根据alignment、positioned节点的绝对位置等信息,对子节点进行布局。

第一步是根据positioned的绝对位置,计算出约束条件后进行布局。

if (childParentData.left != null && childParentData.right != null)
childConstraints = childConstraints.tighten(width: size.width - childParentData.right - childParentData.left);
else if (childParentData.width != null)
childConstraints = childConstraints.tighten(width: childParentData.width);

if (childParentData.top != null && childParentData.bottom != null)
childConstraints = childConstraints.tighten(height: size.height - childParentData.bottom - childParentData.top);
else if (childParentData.height != null)
childConstraints = childConstraints.tighten(height: childParentData.height);

child.layout(childConstraints, parentUsesSize: true);

第二步则是位置的调整,其中坐标的计算如下:

double x;
if (childParentData.left != null) {
x = childParentData.left;
} else if (childParentData.right != null) {
x = size.width - childParentData.right - child.size.width;
} else {
x = _resolvedAlignment.alongOffset(size - child.size).dx;
}

if (x < 0.0 || x + child.size.width > size.width)
_hasVisualOverflow = true;

double y;
if (childParentData.top != null) {
y = childParentData.top;
} else if (childParentData.bottom != null) {
y = size.height - childParentData.bottom - child.size.height;
} else {
y = _resolvedAlignment.alongOffset(size - child.size).dy;
}

if (y < 0.0 || y + child.size.height > size.height)
_hasVisualOverflow = true;

childParentData.offset = new Offset(x, y);

1.6 使用场景

Stack的场景还是比较多的,对于需要叠加显示的布局,一般都可以使用Stack。有些场景下,也可以被其他控件替代,我们应该选择开销较小的控件去实现。

2. IndexedStack

A Stack that shows a single child from a list of children.

2.1 简介

IndexedStack继承自Stack,它的作用是显示第index个child,其他child都是不可见的。所以IndexedStack的尺寸永远是跟最大的子节点尺寸一致。

2.2 例子

在此还是将Stack的例子稍加改造,将index设置为1,也就是显示含文本的Container的节点。

Container(
color: Colors.yellow,
child: IndexedStack(
index: 1,
alignment: const Alignment(0.6, 0.6),
children: [
CircleAvatar(
backgroundImage: AssetImage(‘images/pic.jpg’),
radius: 100.0,
),
Container(
decoration: BoxDecoration(
color: Colors.black45,
),
child: Text(
‘Mia B’,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
),
)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3 源码解析

其绘制代码很简单,因为继承自Stack,布局方面表现基本一致,不同之处在于其绘制的时候,只是将第Index个child进行了绘制。

@override
void paintStack(PaintingContext context, Offset offset) {
if (firstChild == null || index == null)
return;
final RenderBox child = _childAtIndex();
final StackParentData childParentData = child.parentData;
context.paintChild(child, childParentData.offset + offset);
}

2.4 使用场景

如果需要展示一堆控件中的一个,可以使用IndexedStack。有一定的使用场景,但是也有控件可以实现其功能,只不过操作起来可能会复杂一些。

3. GridView

A scrollable, 2D array of widgets.

3.1 简介

GridView在移动端上非常的常见,就是一个滚动的多列列表,实际的使用场景也非常的多。

3.2 布局行为

GridView的布局行为不复杂,本身是尽量占满空间区域,布局行为上完全继承自ScrollView。

3.3 继承关系

Object > Diagnosticable > DiagnosticableTree > Widget > StatelessWidget > ScrollView > BoxScrollView > GridView

从继承关系看,GridView是在ScrollView的基础上封装而来的,这跟移动端的类似。

3.4 示例代码

GridView.count(
crossAxisCount: 2,
children: List.generate(
100,
(index) {
return Center(
child: Text(
‘Item $index’,
style: Theme.of(context).textTheme.headline,
),
);
},
),
);

示例代码直接用了Creating a Grid List中的例子,创建了一个2列总共100个子节点的列表。

3.5 源码解析

默认构造函数如下:

GridView({
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
@required this.gridDelegate,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
double cacheExtent,
List children = const [],
})

同时也提供了如下额外的四种构造方法,方便开发者使用。

GridView.builder
GridView.custom
GridView.count
GridView.extent

3.5.1 属性解析

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

下面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题全套解析,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,下面只是以图片的形式给大家展示一部分。

image

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

image

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,下面只是以图片的形式给大家展示一部分。

[外链图片转存中…(img-H0HiVk24-1714702602958)]

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-ZcxO7BCn-1714702602960)]

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值