final double freeSpace = math.max(0.0, (canFlex ? maxMainSize : 0.0) - allocatedSize);
if (totalFlex > 0 || crossAxisAlignment == CrossAxisAlignment.baseline) {
final double spacePerFlex = canFlex && totalFlex > 0 ? (freeSpace / totalFlex) : double.nan;
child = firstChild;
while (child != null) {
final int flex = _getFlex(child);
if (flex > 0) {
final double maxChildExtent = canFlex ? (child == lastFlexChild ? (freeSpace - allocatedFlexSpace) : spacePerFlex * flex) : double.infinity;
double minChildExtent;
switch (_getFit(child)) {
case FlexFit.tight:
assert(maxChildExtent < double.infinity);
minChildExtent = maxChildExtent;
break;
case FlexFit.loose:
minChildExtent = 0.0;
break;
}
BoxConstraints innerConstraints;
if (crossAxisAlignment == CrossAxisAlignment.stretch) {
switch (_direction) {
case Axis.horizontal:
innerConstraints = new BoxConstraints(minWidth: minChildExtent,
maxWidth: maxChildExtent,
minHeight: constraints.maxHeight,
maxHeight: constraints.maxHeight);
break;
case Axis.vertical:
innerConstraints = new BoxConstraints(minWidth: constraints.maxWidth,
maxWidth: constraints.maxWidth,
minHeight: minChildExtent,
maxHeight: maxChildExtent);
break;
}
} else {
switch (_direction) {
case Axis.horizontal:
innerConstraints = new BoxConstraints(minWidth: minChildExtent,
maxWidth: maxChildExtent,
maxHeight: constraints.maxHeight);
break;
case Axis.vertical:
innerConstraints = new BoxConstraints(maxWidth: constraints.maxWidth,
minHeight: minChildExtent,
maxHeight: maxChildExtent);
break;
}
}
child.layout(innerConstraints, parentUsesSize: true);
final double childSize = _getMainSize(child);
allocatedSize += childSize;
allocatedFlexSpace += maxChildExtent;
crossSize = math.max(crossSize, _getCrossSize(child));
}
if (crossAxisAlignment == CrossAxisAlignment.baseline) {
final double distance = child.getDistanceToBaseline(textBaseline, onlyReal: true);
if (distance != null)
maxBaselineDistance = math.max(maxBaselineDistance, distance);
}
final FlexParentData childParentData = child.parentData;
child = childParentData.nextSibling;
}
}
上面的代码段所做的事情也有两点:
- 为包含flex的child分配剩余的空间
对于每份flex所对应的空间大小,它的计算方式如下:
final double freeSpace = math.max(0.0, (canFlex ? maxMainSize : 0.0) - allocatedSize);
final double spacePerFlex = canFlex && totalFlex > 0 ? (freeSpace / totalFlex) : double.nan;
其中,allocatedSize是不包含flex所占用的空间。当每一份flex所占用的空间计算出来后,则根据交叉轴的设置,对包含flex的child进行调整。
- 计算出baseline值
如果交叉轴的对齐方式为baseline,则计算出最大的baseline值,将其作为整体的baseline值。
switch (_mainAxisAlignment) {
case MainAxisAlignment.start:
leadingSpace = 0.0;
betweenSpace = 0.0;
break;
case MainAxisAlignment.end:
leadingSpace = remainingSpace;
betweenSpace = 0.0;
break;
case MainAxisAlignment.center:
leadingSpace = remainingSpace / 2.0;
betweenSpace = 0.0;
break;
case MainAxisAlignment.spaceBetween:
leadingSpace = 0.0;
betweenSpace = totalChildren > 1 ? remainingSpace / (totalChildren - 1) : 0.0;
break;
case MainAxisAlignment.spaceAround:
betweenSpace = totalChildren > 0 ? remainingSpace / totalChildren : 0.0;
leadingSpace = betweenSpace / 2.0;
break;
case MainAxisAlignment.spaceEvenly:
betweenSpace = totalChildren > 0 ? remainingSpace / (totalChildren + 1) : 0.0;
leadingSpace = betweenSpace;
break;
}
然后,就是将child在主轴方向上按照设置的对齐方式,进行位置调整。上面代码就是计算前后空白区域值的过程,可以看出spaceBetween、spaceAround以及spaceEvenly的差别。
double childMainPosition = flipMainAxis ? actualSize - leadingSpace : leadingSpace;
child = firstChild;
while (child != null) {
final FlexParentData childParentData = child.parentData;
double childCrossPosition;
switch (_crossAxisAlignment) {
case CrossAxisAlignment.start:
case CrossAxisAlignment.end:
childCrossPosition = _startIsTopLeft(flipAxis(direction), textDirection, verticalDirection)
== (_crossAxisAlignment == CrossAxisAlignment.start)
? 0.0
: crossSize - _getCrossSize(child);
break;
case CrossAxisAlignment.center:
childCrossPosition = crossSize / 2.0 - _getCrossSize(child) / 2.0;
break;
case CrossAxisAlignment.stretch:
childCrossPosition = 0.0;
break;
case CrossAxisAlignment.baseline:
childCrossPosition = 0.0;
if (_direction == Axis.horizontal) {
assert(textBaseline != null);
final double distance = child.getDistanceToBaseline(textBaseline, onlyReal: true);
if (distance != null)
childCrossPosition = maxBaselineDistance - distance;
}
break;
}
if (flipMainAxis)
childMainPosition -= _getMainSize(child);
switch (_direction) {
case Axis.horizontal:
childParentData.offset = new Offset(childMainPosition, childCrossPosition);
break;
case Axis.vertical:
childParentData.offset = new Offset(childCrossPosition, childMainPosition);
break;
}
if (flipMainAxis) {
childMainPosition -= betweenSpace;
} else {
childMainPosition += _getMainSize(child) + betweenSpace;
}
child = childParentData.nextSibling;
}
最后,则是根据交叉轴的对齐方式设置,对child进行位置调整,到此,布局结束。
我们可以顺一下整体的流程:
- 计算出flex的总和,并找到最后一个设置了flex的child;
- 对不包含flex的child,根据交叉轴对齐方式,对齐进行调整,并计算出主轴方向上所占区域大小;
- 计算出每一份flex所占用的空间,并根据交叉轴对齐方式,对包含flex的child进行调整;
- 如果交叉轴设置为baseline对齐,则计算出整体的baseline值;
- 按照主轴对齐方式,对child进行调整;
- 最后,根据交叉轴对齐方式,对所有child位置进行调整,完成布局。
1.6 使用场景
Row和Column都是非常常用的布局控件。一般情况下,比方说需要将控件在一行或者一列显示的时候,都可以使用。但并不是说只能使用Row或者Column去布局,也可以使用Stack,看具体的场景选择。
2. Column
在讲解Row的时候,其实是按照Flex的一些布局行为来进行的,包括源码分析,也都是在用Flex进行分析的。Row和Column都是Flex的子类,只是direction参数不同。Column各方面同Row,因此在这里不再另行讲解。
在讲解Flex的时候,也说过是参照了web的Flex布局,如果有相关开发经验的同学,完全可以参照着去理解,这样子更容易去理解它们的用法和原理。
3. 后话
笔者建了一个Flutter学习相关的项目,Github地址,里面包含了笔者写的关于Flutter学习相关的一些文章,会定期更新,也会上传一些学习Demo,欢迎大家关注。
4. 参考
- Row class
- Column class
- MainAxisAlignment enum
- CrossAxisAlignment enum
- MainAxisSize enum
- VerticalDirection enum
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
最后
由于文章篇幅原因,我只把面试题列了出来,详细的答案,我整理成了一份PDF文档,这份文档还包括了还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 ,帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习。
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)**
[外链图片转存中…(img-Ff32QDF8-1710835406314)]
最后
由于文章篇幅原因,我只把面试题列了出来,详细的答案,我整理成了一份PDF文档,这份文档还包括了还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 ,帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习。
需要的朋友可以私信我【答案】或者点击这里免费领取