flutter 布局原理(1),拼多多c++面试题

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

img
img
htt

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

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

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
img

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

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框架在运行时遍历整个组件树,在这过程中 **「向下传递约束,向上传递尺寸」**,以此来确定每个组件的尺寸和大小。


![](https://img-blog.csdnimg.cn/img_convert/66b74a0d530abb87fe6d236b25b4ccb1.png)


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。于是整个布局约束如下:


![](https://img-blog.csdnimg.cn/img_convert/500642658e0c7ef4d2a3db0bf45d8e9e.png)


这里有个问题,就是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,),
);
}


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


![](https://img-blog.csdnimg.cn/img_convert/166a905125246ce913dfcaea074bd584.png)


这里Container为什么是`ConstrainedBox`和`Align`组件?前面说过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。


![](https://img-blog.csdnimg.cn/img_convert/84dbebff8ee3c6bd9367c788ab898bac.png)


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


这就涉及到组件的内部实现了,这里通过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),
);
}
/// …
}


而R**enderPositionedBox**类中,重写**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中p**erformLayout**方法的实现,可以确定该组件最终会给子组件传递一个怎么样的约束。



/// 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,
);
}


其它绘制类的组件基本跟Align大同小异,只要重点看performLayout方法的实现,即可判断出组件提供的约束条件。

  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,
  );
}

其它绘制类的组件基本跟Align大同小异,只要重点看performLayout方法的实现,即可判断出组件提供的约束条件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值