Skip to content

空间适配-FittedBox ​

FittedBox ​

dart
const FittedBox({
  Key? key,
  this.fit = BoxFit.contain, // 适配方式
  this.alignment = Alignment.center, // 对齐方式
  this.clipBehavior = Clip.none, // 是否剪裁
  Widget? child,
})

规则 ​

  1. FittedBox 在布局子组件时会忽略其父组件传递的约束,可以允许子组件无限大,即FittedBox 传递给子组件的约束为(0<=width<=double.infinity, 0<= height <=double.infinity)
  2. 但 FittedBox 自身还是要遵守其父组件传递的约束,并且不管子组件是否溢出 FittedBox,FittedBox 的布局还是正常的

例子 ​

dart
Container(
  constraints: BoxConstraints.expand(width: 50, height: 50),
  color: Colors.red,
  child: FittedBox(
    fit: BoxFit.none,
    child: Container(width: 60, height: 70, color: Colors.blue),
  ),
)

最终是一个 60 * 70 的蓝色矩形,FittedBox 还是在那个位置,但因为其允许子级无限大,则子组件溢出了 FittedBox,覆盖了红色。

可以修改 fit,进行裁剪

单行缩放布局 ​

定义一个可服用行,可根据传入字符串的多少,来控制宽度

dart
MyRow(String text) => Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [Text(text), Text(text), Text(text)],
);

使用

dart
Column(
  children: [
    MyRow(' hahahahahahahahahahaha '),
    FittedBox(child: MyRow(' hahahahahahahahahahaha ')),
    MyRow(' xixi '),
    FittedBox(child: MyRow(' xixi '))
  ],
)

  1. 三个 hahahahahahahahahahaha 的长度加起来已经超出了测试设备的屏幕宽度,所以报溢出警告
  2. 加上 FittedBox 后,就可以按比例缩放至一行显示,但文字的缩小
  3. 三个 xixi 放在一行,因为 Row 指定主轴对齐方式为 spaceEvenly,则在约束的 maxWidth 不是无限大是,Row 的子组件会分配剩余空间
  4. 加上 FittedBox 后,FittedBox 传给 Row 的约束的 maxWidth 为无限大,因此 Row 的最终宽度就是子组件的宽度之和

解决方案 ​

使用 LayoutBuilder 封装一个 SingleLineFittedBox

dart
class SingleLineFittedBox extends StatelessWidget {
 const SingleLineFittedBox({Key? key,this.child}) : super(key: key);
 final Widget? child;

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (_, constraints) {
        return FittedBox(
          child: ConstrainedBox(
            constraints: constraints.copyWith(
              //让 maxWidth 使用屏幕宽度
              maxWidth: constraints.maxWidth
            ),
            child: child,
          ),
        );
      },
    );
  }
}

可以看到 SingleLineFittedBox 包裹的 xixi 满足预期了

但是 SingleLineFittedBox 包裹的 hahahahahahahahahahaha 溢出了,这是因为 SingleLineFittedBox 传给 Row 的 maxWidth 为屏幕宽度,和不加 FittedBox 效果是一样的,所以还要稍加修改

dart
class SingleLineFittedBox extends StatelessWidget {
 const SingleLineFittedBox({Key? key,this.child}) : super(key: key);
 final Widget? child;

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (_, constraints) {
        return FittedBox(
          child: ConstrainedBox(
            constraints: constraints.copyWith(
              minWidth: constraints.maxWidth,
              maxWidth: double.infinity
            ),
            child: child,
          ),
        );
      },
    );
  }
}

将最小宽度(minWidth)约束指定为屏幕宽度

因为Row必须得遵守父组件的约束,所以 Row 的宽度至少等于屏幕宽度,所以就不会出现缩在一起的情况;同时我们将 maxWidth 指定为无限大,则就可以处理数字总长度超出屏幕宽度的情况