Flutter中给widget设置padding

在flutter中给布局和控件设置padding用到的是EdgeInsetsGeometry类,该类位于依赖库中Dart Packages库的flutter/lib/src/painting/edge_insets.dart文件中

设置padding有两种用法

第一种在布局widget中设置padding属性,例如:

new Container(
  padding: const EdgeInsets.all(8.0),
);

new ListView(
  padding: const EdgeInsets.symmetric(horizontal: 8.0),
);

第二种直接使用Padding widgets设置paddng属性,然后在Padding嵌套其他widget

new Padding(
  padding: const EdgeInsets.only(left: 8.0),
  child: new Text("padding"),
);

他们都用到了EdgeInsetsGeometry类的子类EdgeInsets

EdgeInsetsGeometry类有三个子类分别是:

EdgeInsets

EdgeInsetsDirectional

_MixedEdgeInsets:私有子类

EdgeInsetsGeometry

EdgeInsetsGeometry是一个抽象类,其中默认使用的子类是私有子类_MixedEdgeInsets,很多非抽象方法中的操作直接由这个类完成

定义了上下左右,开始,结束6个变量

double get _bottom;
double get _end;
double get _left;
double get _right;
double get _start;
double get _top;

这里只是先定义了变量的get抽象方法,三个子类中会定义具体的变量

 

然后在这6个变量的基础上继续定义了新的变量

/// 判断所有的变量是否都非负,即是否全部大于0
bool get isNonNegative {
  return _left >= 0.0
      && _right >= 0.0
      && _start >= 0.0
      && _end >= 0.0
      && _top >= 0.0
      && _bottom >= 0.0;
}


/// 水平方向上的间距之和
double get horizontal => _left + _right + _start + _end;


/// 垂直防线上的间距之和
double get vertical => _top + _bottom;

/// 整个padding占用空间的大小,用Size类表示
Size get collapsedSize => Size(horizontal, vertical);

/// 用当前的水平方向的值和垂直方向的值将给定的Size宽高增加,返回新的Size
Size inflateSize(Size size) {
  return Size(size.width + horizontal, size.height + vertical);
}

/// 用给出的Size的宽高分别减去当前的水平方向的值和垂直方向的值,返回新的Size
Size deflateSize(Size size) {
  return Size(size.width - horizontal, size.height - vertical);
}

 

下面是抽象属性flipped,含义是使用当前类的6个属性创建一个新的EdgeInsetsGeometry变量,子类中重写该方法,并返回子类的类型。该方法中默认使用了私有子类_MixedEdgeInsets的命名构造方法

    EdgeInsetsGeometry get flipped => _MixedEdgeInsets.fromLRSETB(_right, _left, _end, _start, _bottom, _top);

 

下面是一些运算相关的方法

1对本类的运算

  /// 两个EdgeInsetsGeometry相减,即将6个属性分别相减之后,
  /// 使用私有内部类_MixedEdgeInsets的fromLRSETB方法创建新的对象
  EdgeInsetsGeometry subtract(EdgeInsetsGeometry other) {
    return _MixedEdgeInsets.fromLRSETB(
      _left - other._left,
      _right - other._right,
      _start - other._start,
      _end - other._end,
      _top - other._top,
      _bottom - other._bottom,
    );
  }

  /// 返回两个EdgeInsetsGeometry之和,即将6个属性全部相加之后
  /// 使用私有内部类_MixedEdgeInsets的fromLRSETB方法创建新的对象
  EdgeInsetsGeometry add(EdgeInsetsGeometry other) {
    return _MixedEdgeInsets.fromLRSETB(
      _left + other._left,
      _right + other._right,
      _start + other._start,
      _end + other._end,
      _top + other._top,
      _bottom + other._bottom,
    );
  }

2 重写一些操作符 重写了=运算,对所有类型进行比较,剩下的运算是对double变量进行算术运算,都是抽象方法,由子类实现

  ///只有当类型是EdgeInsetsGeometry并且6个属性都相等的情况下才算是相等
  @override
  bool operator ==(dynamic other) {
    if (other is! EdgeInsetsGeometry)
      return false;
    final EdgeInsetsGeometry typedOther = other;
    return _left == typedOther._left
        && _right == typedOther._right
        && _start == typedOther._start
        && _end == typedOther._end
        && _top == typedOther._top
        && _bottom == typedOther._bottom;
  }
  /// 对EdgeInsetsGeometry取反,等同于 *-1.0 运算
  EdgeInsetsGeometry operator -();
  EdgeInsetsGeometry operator *(double other);//乘
  EdgeInsetsGeometry operator /(double other);//除
  EdgeInsetsGeometry operator ~/(double other);//整除
  EdgeInsetsGeometry operator %(double other);//取余

 

抽象的运算分别是乘,除,整除,取余,剩下加减等操作在子类中定义并实现

 

静态方法lerp

  static EdgeInsetsGeometry lerp(EdgeInsetsGeometry a, EdgeInsetsGeometry b, double t) {
    assert(t != null);
    if (a == null && b == null)
      return null;
    if (a == null)
      return b * t;
    if (b == null)
      return a * (1.0 - t);
    if (a is EdgeInsets && b is EdgeInsets)
      return EdgeInsets.lerp(a, b, t);
    if (a is EdgeInsetsDirectional && b is EdgeInsetsDirectional)
      return EdgeInsetsDirectional.lerp(a, b, t);
    return _MixedEdgeInsets.fromLRSETB(
      ui.lerpDouble(a._left, b._left, t),
      ui.lerpDouble(a._right, b._right, t),
      ui.lerpDouble(a._start, b._start, t),
      ui.lerpDouble(a._end, b._end, t),
      ui.lerpDouble(a._top, b._top, t),
      ui.lerpDouble(a._bottom, b._bottom, t),
    );
  }

该方法返回新的EdgeInsetsGeometry,对参数a和参数b分别进行判断

如果a,b都是空则返回空

如果a空b不空,返回b*t

如果a不空b空,返回a*(1.0-t)

如果a与b类型是相同的子类,则调用对应子类的lerp方法,子类的lerp方法与父类的类似。

以上条件都不满足则,对a和b的6个参数分别与参数t进行lerpDouble运算,并用返回的值创建一个新的_MixedEdgeInsets对象返回。

这个方法的含义根据注释以及运算可以得出,是对两个EdgeInsetsGeometry对象中的每个参数进行线性插值运算,类似于属性动画的匀速渐变效果的运算,参数t是插值因数,从最终调用的lerpDouble可以得出结论代码如下:

/// Linearly interpolate between two numbers.
double lerpDouble(num a, num b, double t) {
  if (a == null && b == null)
    return null;
  a ??= 0.0;
  b ??= 0.0;
  return a + (b - a) * t;
}

这个方法可以理解成算出,从a值到b值在给定的因数t下得出的值,

例如要算出在10秒内从0数到20,每一秒数到几,就可以用上面的公式

1秒 :lerpDouble(0,20,1/10)= 2

2秒:lerpDouble(0,20,2/10)= 4

3秒:lerpDouble(0,20,3/10)= 6

 

resolve方法

EdgeInsets resolve(TextDirection direction);

抽象方法,当前对象根据TextDirection转换成EdgeInsets对象,子类实现

三个子类的区别与联系

EdgeInsets

这个类定义了6个变量中的,_left,_top,_right,_bottom对应的变量,分别是left,top,right,bottom

将_start,_end设置成默认返回0.0,

此类中的所有操作都使用四个方向的值即left,top,right,bottom来执行,start与end保持不变。

只支持left-right,不支持right-left反向布局

 

EdgeInsetsDirectional

这个类定义了6个变量中的,_start,_top,_end,_bottom对应的变量,分别是,start,top,end,bottom

将_left,_right设置成默认返回0.0,

此类中的所有操作都使用四个方向的值即start,top,end,bottom来执行,left与right保持不变。

支持left-right布局,right-left反向布局

 

_MixedEdgeInsets:私有子类,外界不能使用,其他两个外界可以使用

在父类中有些非抽象方法中,使用的就是这个私有子类完成的逻辑,它定义了全部6个变量。

EdgeInsets

常用的五个命名构造函数

  /// 命名构造函数,根据left,top,right,bottom四个方向的值创建EdgeInsets
  const EdgeInsets.fromLTRB(this.left, this.top, this.right, this.bottom);

  /// 把上下左右四个方向的间距都设置成给定的值
  const EdgeInsets.all(double value)
    : left = value,
      top = value,
      right = value,
      bottom = value;

  /// 可设置上下左右 的任意0个1个或多个值,没有设置的值默认为0
  const EdgeInsets.only({
    this.left = 0.0,
    this.top = 0.0,
    this.right = 0.0,
    this.bottom = 0.0
  });

  /// 设置左右对称的间距horizontal,赋值给left和right
  /// 或者上下对称的间距vertical,赋值给top和bottom
  const EdgeInsets.symmetric({
    double vertical = 0.0,
    double horizontal = 0.0,
  }) : left = horizontal,
       top = vertical,
       right = horizontal,
       bottom = vertical;

  /// 根据WindowPadding和比率设置四周间距
  EdgeInsets.fromWindowPadding(ui.WindowPadding padding, double devicePixelRatio)
    : left = padding.left / devicePixelRatio,
      top = padding.top / devicePixelRatio,
      right = padding.right / devicePixelRatio,
      bottom = padding.bottom / devicePixelRatio;

没有间距可以使用EdgeInsets.zero,可以看出它调用了EdgeInsets.only()方法

  /// An [EdgeInsets] with zero offsets in each direction.
  static const EdgeInsets zero = EdgeInsets.only();

 

下面两个方法是对Rect的操作

///把所给的rect按照间隔扩大
Rect inflateRect(Rect rect) {
    return Rect.fromLTRB(rect.left - left, rect.top - top, rect.right + right, rect.bottom + bottom);
  }

///把所给的rect按照间隔缩小
Rect deflateRect(Rect rect) {
    return Rect.fromLTRB(rect.left + left, rect.top + top, rect.right - right, rect.bottom - bottom);
  }

Rect代表一个区域,放大就是在坐标上左侧向左移动,右侧向右移动,上边向上移动,下边向下移动,所以flutter的坐标轴与安卓的坐标轴保持不变

                                               Flutter中给widget设置padding_第1张图片

缩小相反,left增大,right减小,top增大,bottom减小

 

下面是EdgeInsets对象之间的操作

  @override
  EdgeInsetsGeometry subtract(EdgeInsetsGeometry other) {
    if (other is EdgeInsets)
      return this - other;
    return super.subtract(other);
  }

  @override
  EdgeInsetsGeometry add(EdgeInsetsGeometry other) {
    if (other is EdgeInsets)
      return this + other;
    return super.add(other);
  }

  /// Returns the difference between two [EdgeInsets].
  EdgeInsets operator -(EdgeInsets other) {
    return EdgeInsets.fromLTRB(
      left - other.left,
      top - other.top,
      right - other.right,
      bottom - other.bottom,
    );
  }

  /// Returns the sum of two [EdgeInsets].
  EdgeInsets operator +(EdgeInsets other) {
    return EdgeInsets.fromLTRB(
      left + other.left,
      top + other.top,
      right + other.right,
      bottom + other.bottom,
    );
  }

subtract内部调用了 重写运算符 - 内部实现就是用上下左右四个数相减的结果,调用命名构造函数,创建新的EdgeInsets对象

add方法类似

还有父类中定义的 重写运算符实现的方法类似,取反符号可以看做是*-1.0得出的结果

 

resolve方法返回自己本身,因为这个方法含义就是将其他子类转换成EdgeInsets,所以不需要处理

  @override
  EdgeInsets resolve(TextDirection direction) => this;
copyWith调用了only方法
EdgeInsets copyWith({
    double left,
    double top,
    double right,
    double bottom,
}) {
    return EdgeInsets.only(
      left: left ?? this.left,
      top: top ?? this.top,
      right: right ?? this.right,
      bottom: bottom ?? this.bottom,
    );
  }

 

EdgeInsetsDirectional

 

它只有两个构造方法

 const EdgeInsetsDirectional.fromSTEB(this.start, this.top, this.end, this.bottom);


 const EdgeInsetsDirectional.only({
    this.start = 0.0,
    this.top = 0.0,
    this.end = 0.0,
    this.bottom = 0.0
  });

 

resolve方法

  @override
  EdgeInsets resolve(TextDirection direction) {
    assert(direction != null);
    switch (direction) {
      case TextDirection.rtl:
        return EdgeInsets.fromLTRB(end, top, start, bottom);
      case TextDirection.ltr:
        return EdgeInsets.fromLTRB(start, top, end, bottom);
    }
    return null;
  }

在EdgeInsetsDirectional中,根据TextDirection的方向返回不同的EdgeInsets,

如果是右到左方向则end作为left,start作为right

如果是左到右方向则start作为left,end作为right,正常使用

 

_MixedEdgeInsets

唯一的构造函数,6个变量都使用了

const _MixedEdgeInsets.fromLRSETB(this._left, this._right, this._start, this._end, this._top, this._bottom);

 

resolve方法

  @override
  EdgeInsets resolve(TextDirection direction) {
    assert(direction != null);
    switch (direction) {
      case TextDirection.rtl:
        return EdgeInsets.fromLTRB(_end + _left, _top, _start + _right, _bottom);
      case TextDirection.ltr:
        return EdgeInsets.fromLTRB(_start + _left, _top, _end + _right, _bottom);
    }
    return null;
  }

这个方法也对TextDirection的方向进行了判断

如果是右到左方向,用end加上left作为新的left,start加上right作为新的right

如果是左到右方向,用start加上left作为新的left,end加上right作为新的right

你可能感兴趣的:(Flutter,Android)