前言:
这是我参与8月更文挑战的第 14 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战,我准备在本月挑选 31 个以前没有介绍过的组件,进行全面分析和属性介绍。这些文章将来会作为 Flutter 组件集录 的重要素材。希望可以坚持下去,你的支持将是我最大的动力~
一、认识 Padding 组件
说到 Padding ,应该是大家入门 Flutter 时学习的第一批组件。它的功能非常简单,就是为子组件添加边距。本文就回到 梦的起点 ,来好好说说 Padding组件的使用与其源码实现。
1.Padding 基本信息
下面是 Padding 组件类的定义和 构造方法,可以看出它继承自 SingleChildRenderObjectWidget。实例化时必须传入 padding 参数,其中padding 的类型为 EdgeInsetsGeometry 。另外,还能传入一个 child 组件。
final EdgeInsetsGeometry padding;
2. Padding 组件的使用
比如下面的灰色盒子中有一个 Icon 组件。这时想让它四周有 10 的边距,我们就可以通过 Padding 组件完成。
如下 tag1 处,通过 Padding 组件,指定 padding 值,效果如下:
class PaddingDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
height: 100,
width: 100,
alignment: Alignment.topLeft,
color: Colors.black12,
child: const Padding( //<--- tag1
padding: EdgeInsets.all(10),
child: Icon(
Icons.ac_unit,
size: 40,
color: Colors.green,
),
),
);
}
}
无论是可见的还是不可见的组件,都有其尺寸区域。那加上 EdgeInsets.all(10) 边距之后,Padding 组件的尺寸区域是什么?下面有三个选项:
通过布局查看器可以知道,选 A 。我们都知道 padding 是内边距,margin 是外边距。从 Icon 组件的角度来看,似乎是为其添加了 外边距 来实现功能。但使用 Padding 组件,应该站在 Padding 组件的角度来看待问题:这样对于 child 组件就是通过 内边距 ,拓展了 Padding 组件的占位区域。
由于 Padding 组件的边距区域是不可见的,但占据空间,当其他组件并列排布,感觉上是两者之间有一个留白。
其中被包裹的 Icon 组件本身并没有任何变化, Padding 组件可以在任意的组件外嵌套,这种 可插拔 的功能实现模式,是 Flutter 的一大特点,这样可以极大程度地降低组件间的耦合性,使用起来更加灵活。Padding 组件的功能非常简单,但其中的思想是非常值得学习的:
几乎任何组件都可能使用到 padding 属性操作边距,然而框架并没有将 padding 属性作为 Widget 的公共属性。这些通用的属性无法预测有多少,如果都作为 Widget 的公共属性,维护起来自然麻烦, Widget 本身也就自然繁重。而分离出不同的组件实现功能,通过组件组合的进行使用,这样可以各取所需,自然高明许多。
3. 认识 EdgeInsetsGeometry
其实边距本身就是 左上右下 四个数字。Flutter 里将这四个数字抽象为 EdgeInsetsGeometry 。可以看出它是 const 构造,也就是说 EdgeInsetsGeometry 对象一旦创建,就无法修改该对象的属性值。这也是为什么六个属性通过 get 方法获取,却没有 set 方法设置的原因。
EdgeInsetsGeometry 作为抽象类自然是无法直接使用的,其可用的实现类有 EdgeInsets 和 EdgeInsetsDirectional 。
我们最常使用的是 EdgeInsets ,通过 左上右下 来控制边距大小。其中维护了四个属性值,通过构造进行初始化。
主要构造有如下四个:
EdgeInsets.fromLTRB // 指定左、上、右、下、四个边距值(必须传入四参)
EdgeInsets.all // 指定一个值,用于左、上、右、下边距
EdgeInsets.only // 指定左、上、右、下、四个边距值(入参任意)
EdgeInsets.symmetric // 指定水平/竖直边距值
另外,由于其中重载了一下运算符,也就说明,两个 EdgeInsets 对象间可以进行运算符计算。
另外一个子类 EdgeInsetsDirectional 用的比较少,其功能基本一致,只不过是 开始、上、结束、下 的边界语义。一般来说,我们更习惯于 左上右下 的语义,而且 EdgeInsets 字母比较少。
二、 Padding 组件的源码实现
1. Padding 源码分析
它继承自 SingleChildRenderObjectWidget 就说明,该组件需要维护一个 RenderObject 对象的创建及更新。
在 createRenderObject 方法中,创建 RenderPadding ,padding 作为构造入参。在 updateRenderObject 中,对 RenderPadding 对象进行更新。也就是说,添加边距的功能是在 RenderPadding 中实现的。
2. RenderPadding 源码
RenderPadding 中最主要的操作是在 performLayout 方法中进步布局处理。可以看出,如果 child 为空,会将 RenderPadding 的尺寸根据 _resolvedPadding 进行处理。也就是说,即使没有子组件,Padding 也可以有占位区间。
如果子组件非空,那么 RenderPadding 的尺寸会根据 _resolvedPadding 和 子组件的尺寸进行计算得出。其实我们一直说 组件的占位区域其实并不严谨,Widget 本身只是属性配置类而已,真正有尺寸 size 概念的是 RenderObject 。只不过 RenderObject 都有对应的 RenderObjectWidget 进行维护,我们说组件的尺寸,更加形象,容易理解。
最后,在 child 绘制时,可以看出做了偏移处理。这也是为什么加了 Padding 组件后,子组件绘制的位置会变化的原因。
那Padding 的使用方式到这里就介绍完毕,那本文到这里就结束了,谢谢观看,明天见~