具有使用CustomSingleChildLayout
和CustomMultiChildLayout
类的经验的人能够(通过示例)详细解释如何使用它们。
我是Flutter的新手,正在尝试了解如何使用它们。但是,该文档太糟糕了,不清楚。我尝试在Internet上搜索示例,但是没有其他文档。
如果您能提供帮助,我将永远感激不已。
谢谢!
答案 0 :(得分:5)
首先,我想说的是,很高兴能为您提供帮助,因为我可以理解您的挣扎-自己弄清楚这一点是有好处的(特别是因为Flutter文档实际上非常出色,与事实相反似乎很沮丧)。
CustomSingleChildLayout
所做的事在我向您解释CustomMultiChildLayout
之后将显而易见。
CustomMultiChildLayout
此小部件的要点是允许您通过单个功能布局传递给此小部件的子级,即,它们的位置和大小可以相互依赖,这是您无法使用来实现预制的Stack
小部件。
CustomMultiChildLayout(
children: [
// Widgets you want to layout in a customized manner
],
)
现在,您还需要执行另外两个步骤,才能开始布置孩子:
children
的每个孩子都必须是LayoutId
,并且您实际上要将要显示为孩子的小部件传递给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的存在。
layoutChild
,您需要为每个 id ,每个孩子提供精确的一次,它会为您提供{{1 }}。
positionChild
,可让您将位置从Size
更改为您指定的任何偏移量。
我觉得现在这个概念应该很清楚了,这就是为什么我将说明如何为示例Offset(0, 0)
实现委托的原因:
CustomMultiChildLayout
另外两个示例是文档中的一个示例(检查准备第2步),还有一个我写过一段时间的feature_discovery
软件包的真实世界示例:MultiChildLayoutDelegate
implementation和CustomMultiChildLayout
in the build
method。
最后一步是覆盖shouldRelayout
method,它可以通过与旧的委托进行比较,简单地控制是否应在任何给定时间点再次调用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.
),
);
}
}
}
((可选地,您也可以覆盖{{3 }}),并将委托添加到您的performLayout
:
CustomMultiChildLayout
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
作为 id ,但是使用2
可能是处理该问题的最佳方法ID,如果您有特定的ID。
如果您想对布局过程进行动画处理或基于一般的可听性触发它,则可以将enum
传递给Listenable
(例如super
)。
getSize
CustomSingleChildLayout
很好地解释了我上面所描述的内容,在这里您还将看到为什么我说super(relayout: animation)
在理解了CustomSingleChildLayout
的工作原理之后会非常明显:
当多个小部件的大小和位置之间存在复杂的关系时,The documentation是合适的。要控制单个孩子的布局,CustomMultiChildLayout更合适。
这也意味着使用CustomMultiChildLayout
遵循我上面描述的相同原理,但是没有ID,因为只有一个孩子。
您需要改用CustomSingleChildLayout,它有不同的方法来实现布局(它们都具有默认行为,因此从技术上讲,它们对于 override 都是可选的):
SingleChildLayoutDelegate
,相当于我上面传递给CustomSingleChildLayout
的约束。
getConstraintsForChild
,相当于上面的layoutChild
。
其他所有内容都完全相同(请记住,您不需要positionChild
,并且只有一个孩子而不是LayoutId
)。
getPositionForChild
这是children
的基础。
使用此功能需要更深入的Flutter知识,并且再次复杂一些,但是如果您想要更多的自定义设置,则它是更好的选择,因为它的级别更低。与CustomMultiChildLayout
相比,这有一个主要优势(通常有更多控制权):
CustomMultiChildLayout
不能根据其子级本身的大小 (请参见MultiChildRenderObjectWidget
)。
出于明显的原因,我不会在这里解释如何使用CustomMultiChildLayout
,但是如果您有兴趣,可以在2020年1月20日之后签出issue regarding better documentation for the reasoning,在其中我使用MultiChildRenderObjectWidget
广泛地讲-我还将写一篇有关此内容的文章,其中应解释所有这些内容的工作原理。
现在您可以记住MultiChildRenderObjectWidget
是使MultiChildRenderObjectWidget
成为可能的原因,直接使用它会为您带来一些好处,例如不必使用CustomMultiChildLayout
而是可以访问LayoutId
的直接父数据。
我用纯文本(在StackOverflow文本字段中)编写了所有代码,因此,如果有错误,请向我指出,然后我将对其进行修复。