Boxy

该库提供了多个小部件和实用程序,让您无需深入了解框架和最少的样板代码即可创建高级布局。

Flex 布局

一个常见的模式是,当您需要在 `Row` 或 `Column` 中使一个或多个小部件具有与列表中其他子项相同的交叉轴尺寸时,您可以使用 `BoxyRow` 和 `Dominant` 来实现此布局,例如
与列表中的另一个子项相同,您可以使用 `BoxyRow` 和 `Dominant` 来实现此布局,例如

68747470733a2f2f692e7473742e73682f66776b64382e676966

BoxyRow(
  mainAxisSize: MainAxisSize.min,
  children: [
    Child1(),
    Dominant(child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Child2(),
        Child3(),
      ],
    )),
  ],
]);

复杂的自定义布局

对于更复杂的布局,此库提供了 `CustomBoxy`,一个多子项布局小部件,允许您手动创建、
约束、布局和绘制每个子项,类似于 `CustomMultiChildLayout`。

这对于需要其他小部件无法提供的布局非常有用,例如一个子项定位在
其他两个的边界之上

68747470733a2f2f692e7473742e73682f31675638592e706e67

class MyLayout extends StatelessWidget {
  final Widget top;
  final Widget middle;
  final Widget bottom;
  
  // The margin between the middle widget and right edge
  final double inset;
  
  MyLayout({
    @required this.top,
    @required this.middle,
    @required this.bottom,
    @required this.inset,
  });

  @override
  Widget build(context) => CustomBoxy(
    delegate: MyDelegate(inset: inset),
    children: [
      // Use LayoutId to give each child an id
      LayoutId(id: #top, child: top),
      LayoutId(id: #bottom, child: bottom),
      // The middle widget should be rendered above the others
      // so we put it at the bottom of the list
      LayoutId(id: #middle, child: middle),
    ],
  );
}

class MyDelegate extends BoxyDelegate {
  final double inset;

  MyDelegate({@required this.inset});
  
  @override
  Size layout() {
    // Get each child handle by a Symbol id
    var top = getChild(#top);
    var middle = getChild(#middle);
    var bottom = getChild(#bottom);
    
    // Children should have unbounded height
    var topConstraints = constraints.widthConstraints();
    
    // Lay out and position top widget
    var topSize = title.layout(topConstraints);
    top.position(Offset.zero);
    
    // Lay out and position middle widget using size of top widget
    var middleSize = middle.layout(BoxConstraints());
    middle.position(Offset(
      topSize.width - (middle.width + inset),
      topSize.height - middle.height / 2,
    ));
    
    // Lay out bottom widget
    var bottomSize = info.layout(topConstraints.tighten(
      // Bottom widget should be same width as top widget
      width: topSize.width,
    ));
    
    // Position bottom widget directly below top widget
    bottom.position(Offset(0, topSize.height));
    
    // Calculate total size
    return Size(
      topSize.width,
      topSize.height + bottomSize.height,
    );
  }
  
  // Check if any properties have changed
  @override
  bool shouldRelayout(MyDelegate old) => old.inset != inset;
}

请参阅 产品图块 示例以了解此
布局的实现,以及 CustomBoxy 的文档以
获取更多信息。

Sliver 容器

是否曾想为 SliverList 添加框装饰?sliver
提供了 `SliverContainer`,它允许您使用框小部件作为 sliver 的前景或背景

68747470733a2f2f692e7473742e73682f756137324c2e676966

此卡片效果可以使用 `SliverCard` 实现

SliverCard(
  color: Colors.white,
  clipBehavior: Clip.antiAlias,
  sliver: SliverList(...),
)

以下示例使用 `SliverContainer` 为 `SliverList` 添加圆角蓝色边框

SliverContainer(
  // How far the background will extend off-screen, prevents the border
  // from shrinking as the sliver is scrolled out of view
  bufferExtent: 12.0,
  
  // The background and foreground are layed out to cover the visible
  // space of the sliver
  background: DecoratedBox(
    border: Border.all(
      color: Colors.blue,
      width: 2,
    ),
    borderRadius: BorderRadius.circular(12),
  ),

  margin: EdgeInsets.all(8.0),
  padding: EdgeInsets.all(8.0),
  sliver: SliverList(...),
)

实用工具

`utils` 库提供了具有轴相关性的扩展方法
方法和构造函数。这些扩展使编写方向无关的数学计算变得更加
容易。

方法完整列表

BoxConstraintsAxisUtil.create
BoxConstraintsAxisUtil.expand
BoxConstraintsAxisUtil.tightFor
BoxConstraintsAxisUtil.tightForFinite
BoxConstraints.hasTightAxis
BoxConstraints.hasTightCrossAxis
BoxConstraints.hasBoundedAxis
BoxConstraints.hasBoundedCrossAxis
BoxConstraints.hasInfiniteAxis
BoxConstraints.hasInfiniteCrossAxis
BoxConstraints.maxAxis
BoxConstraints.minAxis
BoxConstraints.maxCrossAxis
BoxConstraints.minCrossAxis
BoxConstraints.tightenAxis
BoxConstraints.constrainAxisDimensions
BoxConstraints.constrainAxis
BoxConstraints.constrainCrossAxis
BoxConstraints.copyWithAxis
BoxConstraints.axisConstraints
BoxConstraints.crossAxisConstraints
Axis.cross
Axis.direction
Axis.crossDirection
VerticalDirection.reversed
VerticalDirection.direction
AxisDirection.axis
AxisDirection.crossAxis
AxisDirection.isReverse
AxisDirection.isForward
AxisDirection.reversed
AxisDirection.ccw
AxisDirection.cw
AxisDirection.operator+
AxisDirection.operator-
RenderBox.getMinIntrinsicAxis
RenderBox.getMinIntrinsicCrossAxis
RenderBox.getMaxIntrinsicAxis
RenderBox.getMaxIntrinsicCrossAxis
OffsetAxisUtil.create
OffsetAxisUtil.direction
Offset.axisOffset
Offset.crossAxisOffset
Offset.directionExtent
SizeAxisUtil.create
SizeAxisUtil.from
SizeAxisUtil.crossFrom
Size.axisSize
Size.crossAxisSize
EdgeInsetsAxisUtil.create
EdgeInsetsAxisUtil.symmetric
EdgeInsetsAxisUtil.direction
EdgeInsets.directionExtent
AxisSizedBox

GitHub

https://github.com/PixelToast/flutter-boxy