拥有使用CustomSingleChildLayout和CustomMultiChildLayout类经验的人能否详细解释(带示例)如何使用它们。
CustomSingleChildLayout
CustomMultiChildLayout
我是Flutter的新手,正在尝试了解如何使用它们。但是,该文档太糟糕了,不清楚。我尝试在互联网上搜索示例,但没有其他文档。
如果您能帮助我,我将万分感谢。
谢谢!
首先,我想说的是,很高兴为您提供帮助,因为我可以理解您的工作-自己解决问题也有好处(文档很棒)。
CustomSingleChildLayout在我CustomMultiChildLayout向您解释后,将会明白什么。
这个小部件的要点是允许您将传递给该小部件的子项 布置 在一个函数中,即,它们的位置和大小可以相互依赖,这是 无法 使用例如预制Stack小部件实现的。
Stack
CustomMultiChildLayout( children: [ // Widgets you want to layout in a customized manner ], )
现在,您还需要执行 两个步骤 才能开始布置孩子:
children
LayoutId
id
CustomMultiChildLayout( children: [ LayoutId( id: 1, // The id can be anything, i.e. any Object, also an enum value. child: Text('Widget one'), // This is the widget you actually want to show. ), LayoutId( id: 2, // You will need to refer to that id when laying out your children. child: Text('Widget two'), ), ], )
MultiChildLayoutDelegate
class YourLayoutDelegate extends MultiChildLayoutDelegate { // You can pass any parameters to this class because you will instantiate your delegate // in the build function where you place your CustomMultiChildLayout. // I will use an Offset for this simple example. YourLayoutDelegate({this.position}); final Offset position; }
现在,所有设置已完成,您可以开始实施实际布局。您可以使用三种方法:
hasChild,可让您检查是否将特定 ID (记住LayoutId?)传递给children,即是否存在该ID的子代。
hasChild
layoutChild,您需要为每个孩子的每个 id 调用一次,只需提供 一次即可 ,它将给您Size那个孩子的。
layoutChild
Size
positionChild,您可以将位置从更改为Offset(0, 0)指定的任何偏移量。
positionChild
Offset(0, 0)
我觉得现在这个概念应该很清楚了,这就是为什么我将说明如何为示例实现委托的原因CustomMultiChildLayout:
class YourLayoutDelegate extends MultiChildLayoutDelegate { YourLayoutDelegate({this.position}); final Offset position; @override void performLayout(Size size) { // `size` is the size of the `CustomMultiChildLayout` itself. Size leadingSize = Size.zero; // If there is no widget with id `1`, the size will remain at zero. // Remember that `1` here can be any **id** - you specify them using LayoutId. if (hasChild(1)) { leadingSize = layoutChild( 1, // The id once again. BoxConstraints.loose(size), // This just says that the child cannot be bigger than the whole layout. ); // No need to position this child if we want to have it at Offset(0, 0). } if (hasChild(2)) { final secondSize = layoutChild( 2, BoxConstraints( // This is exactly the same as above, but this can be anything you specify. // BoxConstraints.loose is a shortcut to this. maxWidth: size.width, maxHeight: size.height, ), ); positionChild( 2, Offset( leadingSize.width, // This will place child 2 to the right of child 1. size.height / 2 - secondSize.height / 2, // Centers the second child vertically. ), ); } } }
其他两个例子是从文档(检查准备一个 第2步 )和 真实世界 我写的一段时间例如背部feature_discovery包:MultiChildLayoutDelegate执行和CustomMultiChildLayout在build方法。
feature_discovery
build
最后一步是重写shouldRelayoutmethod,该方法performLayout通过与旧的委托进行比较(可选地也可以重写getSize)并将委托添加到您的方法中,简单地控制是否应在任何给定时间点再次调用CustomMultiChildLayout:
shouldRelayout
performLayout
getSize
class YourLayoutDelegate extends MultiChildLayoutDelegate { YourLayoutDelegate({this.position}); final Offset position; @override void performLayout(Size size) { // ... (layout code from above) } @override bool shouldRelayout(YourLayoutDelegate oldDelegate) { return oldDelegate.position != position; } } CustomMultiChildLayout( delegate: YourLayoutDelegate(position: Offset.zero), children: [ // ... (your children wrapped in LayoutId's) ], )
在此示例中,我使用1和2作为 id ,但是enum如果您有特定的ID ,使用an 可能是处理ID的最佳方法。
1
2
enum
如果您想对布局过程进行动画处理或通常基于可听类触发它,则可以将传递Listenable给super(例如super(relayout: animation))。
Listenable
super
super(relayout: animation)
该文档很好地解释了我上面所描述的内容,在这里您还将了解为什么我说了这CustomSingleChildLayout一点,但在理解其CustomMultiChildLayout工作原理之后将非常明显:
如果多个小部件的大小和位置之间存在复杂的关系,则CustomMultiChildLayout是合适的。要控制单个孩子的布局,CustomSingleChildLayout更合适。
这也意味着使用CustomSingleChildLayout遵循我上面描述的相同原理,但是没有ID,因为只有一个孩子。 您需要使用SingleChildLayoutDelegate相反的方法,该方法具有不同的方法来实现布局(它们都具有默认行为,因此从技术上讲,它们都是可选的,可以 覆盖 ):
SingleChildLayoutDelegate
getConstraintsForChild,相当于我layoutChild上面传递的约束。
getConstraintsForChild
getPositionForChild,相当于positionChild上述内容。
getPositionForChild
其他所有内容都完全相同(请记住,您不需要LayoutId,只有一个孩子而不是children)。
MultiChildRenderObjectWidget
这是CustomMultiChildLayout建立在上面的。 使用此功能需要更深入的Flutter知识,并且再次复杂一些,但是如果您需要更多的自定义设置,则它是更好的选择,因为它的级别更低。与(通常有更多控制权)相比,这具有一个 主要 优势CustomMultiChildLayout:
CustomMultiChildLayout 无法 根据其子项确定 自身 _ 大小_ (请参见有关更好的文档说明)。
MultiChildRenderObjectWidget出于明显的原因,我不会在此说明如何使用。但是,如果您有兴趣,可以查看我在2020年1月20日之后提交给Flutter Clock挑战赛的内容,我在其中MultiChildRenderObjectWidget广泛使用- 您还可以阅读有关此内容的文章,这应该解释所有工作原理。
现在您可以记住,这MultiChildRenderObjectWidget是有CustomMultiChildLayout可能的,直接使用它会为您带来一些好处,例如不必使用LayoutId,而是可以直接访问RenderObject的父数据。
RenderObject
我用纯文本(在文本字段中)编写了所有代码,因此,如果有错误,请向我指出,然后我将对其进行修复。