【Flutter 组件集录】Padding | 8 月更文挑战

2022-03-18 15:38:57 浏览数 (1)

一、认识 Padding 组件

说到 Padding ,应该是大家入门 Flutter 时学习的第一批组件。它的功能非常简单,就是为子组件添加边距。本文就回到 梦的起点 ,来好好说说 Padding组件的使用与其源码实现。

1.Padding 基本信息

下面是 Padding 组件类的定义构造方法,可以看出它继承自 SingleChildRenderObjectWidget。实例化时必须传入 padding 参数,其中padding 的类型为 EdgeInsetsGeometry 。另外,还能传入一个 child 组件。

代码语言:javascript复制
final EdgeInsetsGeometry padding;
2. Padding 组件的使用

比如下面的灰色盒子中有一个 Icon 组件。这时想让它四周有 10 的边距,我们就可以通过 Padding 组件完成。

如下 tag1 处,通过 Padding 组件,指定 padding 值,效果如下:

代码语言:javascript复制
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 作为抽象类自然是无法直接使用的,其可用的实现类有 EdgeInsetsEdgeInsetsDirectional

我们最常使用的是 EdgeInsets ,通过 左上右下 来控制边距大小。其中维护了四个属性值,通过构造进行初始化。

主要构造有如下四个:

代码语言:javascript复制
EdgeInsets.fromLTRB  // 指定左、上、右、下、四个边距值(必须传入四参)
EdgeInsets.all       // 指定一个值,用于左、上、右、下边距
EdgeInsets.only      // 指定左、上、右、下、四个边距值(入参任意)
EdgeInsets.symmetric // 指定水平/竖直边距值

另外,由于其中重载了一下运算符,也就说明,两个 EdgeInsets 对象间可以进行运算符计算。

另外一个子类 EdgeInsetsDirectional 用的比较少,其功能基本一致,只不过是 开始、上、结束、下 的边界语义。一般来说,我们更习惯于 左上右下 的语义,而且 EdgeInsets 字母比较少。

二、 Padding 组件的源码实现
1. Padding 源码分析

它继承自 SingleChildRenderObjectWidget 就说明,该组件需要维护一个 RenderObject 对象的创建及更新。

createRenderObject 方法中,创建 RenderPaddingpadding 作为构造入参。在 updateRenderObject 中,对 RenderPadding 对象进行更新。也就是说,添加边距的功能是在 RenderPadding 中实现的。

2. RenderPadding 源码

RenderPadding 中最主要的操作是在 performLayout 方法中进步布局处理。可以看出,如果 child 为空,会将 RenderPadding 的尺寸根据 _resolvedPadding 进行处理。也就是说,即使没有子组件,Padding 也可以有占位区间。

如果子组件非空,那么 RenderPadding 的尺寸会根据 _resolvedPadding 和 子组件的尺寸进行计算得出。其实我们一直说 组件的占位区域其实并不严谨,Widget 本身只是属性配置类而已,真正有尺寸 size 概念的是 RenderObject 。只不过 RenderObject 都有对应的 RenderObjectWidget 进行维护,我们说组件的尺寸,更加形象,容易理解。

最后,在 child 绘制时,可以看出做了偏移处理。这也是为什么加了 Padding 组件后,子组件绘制的位置会变化的原因。

Padding 的使用方式到这里就介绍完毕,那本文到这里就结束了,谢谢观看,明天见~

0 人点赞