当前位置:   article > 正文

flutter 布局原理,2024年最新熬夜整理小米HarmonyOS鸿蒙面试题

flutter 布局原理,2024年最新熬夜整理小米HarmonyOS鸿蒙面试题

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新HarmonyOS鸿蒙全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img

img
img
htt

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注鸿蒙)
img

正文

}

if (decoration != null) {
current = DecoratedBox(decoration: decoration!, child: current);
}

if (foregroundDecoration != null) {
current = DecoratedBox(
decoration: foregroundDecoration!,
position: DecorationPosition.foreground,
child: current,
);
}

if (constraints != null) {
current = ConstrainedBox(constraints: constraints!, child: current);
}

if (margin != null) {
current = Padding(padding: margin!, child: current);
}

if (transform != null) {
current = Transform(transform: transform!, alignment: transformAlignment, child: current);
}

return current!;
}

组合类基本不参与ui的绘制,都是通过绘制类的组合来实现功能。

3、flutter布局约束

flutter中有两种布局约束BoxConstraints盒约束和SliverConstraints线性约束,如Align、Padding、ConstrainedBox使用的是盒约束。

BoxConstraints盒约束是指flutter框架在运行时遍历整个组件树,在这过程中 「向下传递约束,向上传递尺寸」,以此来确定每个组件的尺寸和大小。

BoxConstraints类由4个属性组成,最小宽度minWidth、最大宽度maxWidth、最小高度minHeight、最大高度maxHeight

BoxConstraints({
this.minWidth,
this.maxWidth,
this.minHeight,
this.maxHeight,
});

根据这4个属性的变化,可以分为“紧约束(tight)”、“松约束(loose)”、“无界约束”、“有界约束”。

紧约束:最小宽(高)度和最大宽(高)度值相等,此时它是一个固定宽高的约束。

BoxConstraints.tight(Size size)
minWidth = size.width,
maxWidth = size.width,
minHeight = size.height,
maxHeight = size.height;

松约束:最小宽(高)值为0,最大宽(高)大于0,此时它是一个约束范围。

BoxConstraints.loose(Size size)
minWidth = 0.0,
maxWidth = size.width,
minHeight = 0.0,
maxHeight = size.height;

无界约束:最小宽(高)和最大宽(高)值存在double.infinity(无限)。

BoxConstraints.expand({double? width, double? height})
minWidth = width ?? double.infinity,
maxWidth = width ?? double.infinity,
minHeight = height ?? double.infinity,
maxHeight = height ?? double.infinity;

有界约束:最小宽(高)和最大宽(高)值均为固定值。

BoxConstraints(100, 300, 100, 300)

4、Container布局行为解惑

了解了BoxConstraints布局约束,回到本文最开始的问题。

/// 例一
@override
Widget build(BuildContext context) {
return Container(
width: 300,
height: 300,
color: Colors.amber,
child: Container(width: 50, height: 50, color: Colors.red,),
);
}

例一中,两个固定宽高的Container,为什么子容器铺满了全屏?

根据BoxConstraints布局约束,遍历整个组件树,最开始的root是树的起点,它向下传递的是一个紧约束。因为是移动设备,root即是屏幕的大小,假设屏幕宽414、高896。于是整个布局约束如下:

这里有个问题,就是Container分明已经设置了固定宽高,为什么无效?

因为父级向下传递的约束,子组件必须严格遵守。这里Container容器设置的宽高超出了父级的约束范围,就会自动被忽略,采用符合约束的值。

例一两上Container都被铺满屏幕,而最底下的红色Container叠到了最上层,所以最终显示红色。

/// 例二
@override
Widget build(BuildContext context) {
return Container(
width: 300,
height: 300,
color: Colors.amber,
alignment: Alignment.center,
child: Container(width: 50, height: 50, color: Colors.red,),
);
}

例二也同样可以根据布局约束求证,如下图:

这里Container为什么是ConstrainedBoxAlign组件?前面说过Container是一个组合组件,它是由多个原子组件组成的。根据例二,它是由ConstrainedBox和Align嵌套而成。

Align提供给子组件的是一个松约束,所以容器自身设置50宽高值是在合理范围的,因此生效,屏幕上显示的就是50像素的红色方块。ConstrainedBox受到的是紧约束,所以自身的300宽高被忽略,显示的是铺满屏幕的黄色块。

/// 例三
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: 300,
height: 300,
color: Colors.amber,
alignment: Alignment.center,
child: Container(width: 50, height: 50, color: Colors.red,),
),
);
}

例三中Scaffold向下传递的是一个松约束,所以黄色Container的宽高根据自身设置的300,在合理的范围内,有效。Container再向下传递的也是松约束,最终红色Container宽高为50。

这里还有个问题,怎么确定组件向下传递的是紧约束还是松约束?

这就涉及到组件的内部实现了,这里通过Align举个例。

Align是一个绘制组件,它能够进行界面的布局和绘制,这是因为Align的继承链为:

Align -> SingleChildRenderObjectWidget -> RenderObjectWidget

Align需要重写createRenderObject方法,返回RenderObject的实现,这里Align返回的是RenderPositionedBox,所以核心内容就在这个类中

class Align extends SingleChildRenderObjectWidget {
/// …
@override
RenderPositionedBox createRenderObject(BuildContext context) {
return RenderPositionedBox(
alignment: alignment,
widthFactor: widthFactor,
heightFactor: heightFactor,
textDirection: Directionality.maybeOf(context),
);
}
/// …
}

而RenderPositionedBox类中,重写performLayout方法,该方法用于根据自身约束条件,计算出子组件的布局,再根据子组件的尺寸设置自身的尺寸,形成一个至下而上,由上到下的闭环,最终实现界面的整个绘制。

RenderPositionedBox -> RenderAligningShiftedBox -> RenderShiftedBox -> RenderBox

class RenderPositionedBox extends RenderAligningShiftedBox {
/// …
@override
void performLayout() {
final BoxConstraints constraints = this.constraints; // 自身的约束大小
final bool shrinkWrapWidth = _widthFactor != null || constraints.maxWidth == double.infinity;
final bool shrinkWrapHeight = _heightFactor != null || constraints.maxHeight == double.infinity;
/// 存在子组件
if (child != null) {
/// 开始布局子组件
child!.layout(constraints.loosen(), parentUsesSize: true);
/// 根据子组件的尺寸设置自身尺寸
size = constraints.constrain(Size(
shrinkWrapWidth ? child!.size.width * (_widthFactor ?? 1.0) : double.infinity,
shrinkWrapHeight ? child!.size.height * (_heightFactor ?? 1.0) : double.infinity,
));
/// 计算子组件的位置
alignChild();
} else {
/// 不存在子组件
size = constraints.constrain(Size(
shrinkWrapWidth ? 0.0 : double.infinity,
shrinkWrapHeight ? 0.0 : double.infinity,
));
}
}
/// …
}

根据Align中performLayout方法的实现,可以确定该组件最终会给子组件传递一个怎么样的约束。

/// constraints.loosen提供的是一个松约束
child!.layout(constraints.loosen(), parentUsesSize: true);

/// loosen方法
BoxConstraints loosen() {
assert(debugAssertIsValid());
/// BoxConstraints({double minWidth = 0.0, double maxWidth = double.infinity, double minHeight = 0.0, double maxHeight = double.infinity})
return BoxConstraints(
maxWidth: maxWidth,
maxHeight: maxHeight,
);
}

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

return BoxConstraints(
maxWidth: maxWidth,
maxHeight: maxHeight,
);
}

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
[外链图片转存中…(img-md8aLvMQ-1713124737693)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/687926
推荐阅读
相关标签
  

闽ICP备14008679号