当前位置: 首页 > 工具软件 > Aspect Ratio > 使用案例 >

使用 AspectRatio Widget

莫飞翮
2023-12-01

AspectRatio widget 是用来约束宽高比例的,如果你需要 widget 必须要有一定的宽高比,这个组件就很有用。

但 AspectRatio 并不总是如你所愿,我一度想直接设置宽高达到同样的目的,但当你了解了它的逻辑之后,发现这样做并不明智,因为即使是直接设置高度,这些逻辑也是少不了的。

AspectRatio 需要父容器至少 width 或 height 是有边界的。

想想也是合理的。如果约束是没有边界的,而 AspectRatio 本身又没有宽高属性,AspectRatio 就无法设置宽高,只能都是无限,就和宽高有比例这个要求相矛盾。

AspectRatio 的尺寸的计算逻辑

  1. 如果父元素的宽高都没有边界,抛异常。
  2. 如果收到的是 tight 约束,那么相当于 AspectRatio 无效,不会起到任何作用,只会透传约束。
  3. 优先以宽度为准,按比例设置高度。如果宽度无限,以高度为准按比例设置宽度。
  4. 无论是高度还是宽度都必须在约束的范围内。

AspectRatio 的代码逻辑

决定宽高的代码

 Size _applyAspectRatio(BoxConstraints constraints) {
    assert(constraints.debugAssertIsValid());
    assert(() {
      if (!constraints.hasBoundedWidth && !constraints.hasBoundedHeight) {
        throw FlutterError(
          '$runtimeType has unbounded constraints.\n'
          'This $runtimeType was given an aspect ratio of $aspectRatio but was given '
          'both unbounded width and unbounded height constraints. Because both '
          "constraints were unbounded, this render object doesn't know how much "
          'size to consume.',
        );
      }
      return true;
    }());

    if (constraints.isTight) {
      return constraints.smallest;
    }

    double width = constraints.maxWidth;
    double height;

    // We default to picking the height based on the width, but if the width
    // would be infinite, that's not sensible so we try to infer the height
    // from the width.
    if (width.isFinite) {
      height = width / _aspectRatio;
    } else {
      height = constraints.maxHeight;
      width = height * _aspectRatio;
    }

    // Similar to RenderImage, we iteratively attempt to fit within the given
    // constraints while maintaining the given aspect ratio. The order of
    // applying the constraints is also biased towards inferring the height
    // from the width.

    if (width > constraints.maxWidth) {
      width = constraints.maxWidth;
      height = width / _aspectRatio;
    }

    if (height > constraints.maxHeight) {
      height = constraints.maxHeight;
      width = height * _aspectRatio;
    }

    if (width < constraints.minWidth) {
      width = constraints.minWidth;
      height = width / _aspectRatio;
    }

    if (height < constraints.minHeight) {
      height = constraints.minHeight;
      width = height * _aspectRatio;
    }

    return constraints.constrain(Size(width, height));
  }

定好自己的宽高后,把 child 设置成和自己一样宽高

  @override
  void performLayout() {
    size = computeDryLayout(constraints);
    if (child != null) {
      child!.layout(BoxConstraints.tight(size));
    }
  }

AspectRatio 的 renderObject 继承自 RenderProxyBox。只可以有一个child,没有 alignment 属性,不能摆放 child的位置。

AspectRatio 的 aspectRatio 参数要求是 大于0 的 double ,但是一般都是用分数的形式来写,这样可读性会更好些。

AspectRatio(
      aspectRatio: 1 / 2,
);
 类似资料: