Zunächst möchte ich sagen, dass ich Ihnen gerne dabei helfen kann, da ich Ihre Kämpfe verstehen kann - es hat auch Vorteile, es selbst herauszufinden (die Dokumentation ist erstaunlich).
Was CustomSingleChildLayout
passiert, wird offensichtlich sein, nachdem ich CustomMultiChildLayout
es Ihnen erklärt habe.
Mit diesem Widget können Sie die untergeordneten Elemente, die Sie an dieses Widget übergeben, in einer einzigen Funktion anordnen, dh ihre Positionen und Größen können voneinander abhängen. Dies können Sie beispielsweise mit dem vorgefertigten Widget nicht erreichenStack
.
CustomMultiChildLayout(
children: [
// Widgets you want to layout in a customized manner
],
)
Jetzt müssen Sie noch zwei weitere Schritte ausführen, bevor Sie Ihre Kinder auslegen können:
- Jedes Kind, an das Sie übergeben,
children
muss LayoutId
ein Kind sein, und Sie übergeben das Widget, das Sie tatsächlich als Kind anzeigen möchten LayoutId
. Sie id
identifizieren Ihre Widgets eindeutig und machen sie beim Layout zugänglich:
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'),
),
],
)
- Sie müssen eine
MultiChildLayoutDelegate
Unterklasse erstellen , die den Layoutteil behandelt. Die Dokumentation hier scheint sehr ausführlich zu sein.
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;
}
Jetzt ist die gesamte Einrichtung abgeschlossen und Sie können mit der Implementierung des eigentlichen Layouts beginnen. Dafür gibt es drei Methoden:
hasChild
Hiermit können Sie überprüfen, ob eine bestimmte ID (erinnern Sie sich LayoutId
?) an die übergeben wurde children
, dh ob ein Kind dieser ID vorhanden ist.
layoutChild
, die Sie für jede ID , jedes Kind, genau einmal angeben müssen , und es gibt Ihnen die Size
von diesem Kind.
positionChild
Hiermit können Sie die Position von Offset(0, 0)
einem beliebigen Versatz ändern .
Ich bin der Meinung, dass das Konzept jetzt ziemlich klar sein sollte, weshalb ich veranschaulichen werde, wie ein Delegierter für das Beispiel implementiert wird 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.
),
);
}
}
}
Zwei weitere Beispiele sind die, aus der Dokumentation (Prüfung Vorbereitung Schritt 2 ) und einer realen Welt Beispiel , das ich vor einiger Zeit für das schrieb feature_discovery
Paket: MultiChildLayoutDelegate
Umsetzung und CustomMultiChildLayout
in derbuild
Methode .
Der letzte Schritt besteht darin, die shouldRelayout
Methode zu überschreiben , mit der einfach gesteuert wird, ob performLayout
zu einem bestimmten Zeitpunkt erneut aufgerufen werden soll, indem sie mit einem alten Delegaten verglichen wird (optional können Sie diese auch überschreiben getSize
) und den Delegaten zu Ihrem 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)
],
)
Überlegungen
Früher habe ich 1
und 2
wie die ID in diesem Beispiel s, wobei jedoch eine enum
ist wahrscheinlich der beste Weg , um die IDs zu handhaben, wenn Sie bestimmte IDs haben.
Sie können ein Listenable
an super
(z. B. super(relayout: animation)
) übergeben, wenn Sie den Layoutprozess animieren oder basierend auf einem allgemein hörbaren Element auslösen möchten.
Die Dokumentation erklärt, was ich oben wirklich gut beschrieben habe, und hier werden Sie auch sehen, warum ich gesagt habe, dass CustomSingleChildLayout
dies sehr offensichtlich sein wird, nachdem Sie verstanden haben, wie es CustomMultiChildLayout
funktioniert:
CustomMultiChildLayout ist geeignet, wenn komplexe Beziehungen zwischen der Größe und Positionierung mehrerer Widgets bestehen. Um das Layout eines einzelnen untergeordneten Elements zu steuern, ist CustomSingleChildLayout besser geeignet.
Dies bedeutet auch, dass die Verwendung CustomSingleChildLayout
den gleichen Prinzipien folgt, die ich oben beschrieben habe, jedoch ohne IDs, da es nur ein einziges Kind gibt.
Sie müssen SingleChildLayoutDelegate
stattdessen ein verwenden, das unterschiedliche Methoden zum Implementieren des Layouts hat (alle haben Standardverhalten, sodass sie technisch alle optional überschrieben werden können ):
Alles andere ist genau das gleiche (denken Sie daran, dass Sie nicht brauchen LayoutId
und nur ein einziges Kind haben children
).
Darauf baut CustomMultiChildLayout
man auf.
Dies zu verwenden erfordert noch tiefere Kenntnisse über Flutter und ist wiederum etwas komplizierter, aber es ist die bessere Option, wenn Sie mehr Anpassungen wünschen, da es noch niedriger ist. Dies hat einen großen Vorteil gegenüber CustomMultiChildLayout
(im Allgemeinen gibt es mehr Kontrolle):
CustomMultiChildLayout
Größe kann nicht selbst auf der Grundlage ihrer Kinder (siehe Frage in Bezug auf eine bessere Dokumentation für die Begründung ).
Ich werde MultiChildRenderObjectWidget
aus offensichtlichen Gründen nicht erklären, wie man es hier benutzt, aber wenn Sie interessiert sind, können Sie meine Einreichung zur Flutter Clock Challenge nach dem 20. Januar 2020 MultiChildRenderObjectWidget
lesen , in der ich sie ausgiebig benutze - Sie können auch einen Artikel darüber lesen , Das sollte ein bisschen erklären, wie das alles funktioniert.
Im Moment können Sie sich daran erinnern, dass dies möglich MultiChildRenderObjectWidget
ist. Wenn Sie CustomMultiChildLayout
es direkt verwenden, erhalten Sie einige nützliche Vorteile, z. B. dass Sie es nicht verwenden müssen LayoutId
und stattdessen RenderObject
direkt auf die übergeordneten Daten des Benutzers zugreifen können.
Lustige Tatsache
Ich habe den gesamten Code im Klartext geschrieben (im Textfeld StackOverflow). Wenn also Fehler auftreten, weisen Sie mich darauf hin, und ich werde sie beheben.