Come utilizzare CustomMultiChildLayout e CustomSingleChildLayout in Flutter


10

Qualcuno con esperienza nell'uso CustomSingleChildLayoute CustomMultiChildLayoutlezioni può essere in grado di spiegare in dettaglio (con esempi) su come usarli.

Sono nuovo di Flutter e sto cercando di capire come usarli. Tuttavia, la documentazione è orribile e non è chiara. Ho cercato di setacciare Internet per esempi, ma non c'è altra documentazione.

Le sarei eternamente grato se potessi aiutare.

Grazie!


Potresti per favore aggiungere in cosa vuoi usarli?
João Soares,

@ JoãoSoares Non ti preoccupare perché sto scrivendo una risposta esauriente.
creativecreatorormaybenot

Grandi aspettative quindi!
João Soares,

@ JoãoSoares Fatto, fatemi sapere se avete correzioni.
creativecreatorormaybenot

@creativecreatorormaybenot Sarebbe molto improbabile. Ho visto le tue risposte prima. Ottima risposta, come sempre.
João Soares,

Risposte:


20

Prima di tutto, voglio dire che sono felice di aiutarti in questo perché posso capire le tue lotte - ci sono anche vantaggi a capirlo da soli (la documentazione è incredibile).

Ciò CustomSingleChildLayoutche sarà ovvio dopo che ti ho spiegato CustomMultiChildLayout.

CustomMultiChildLayout

Il punto di questo widget è che ti consente di disporre i bambini che passi a questo widget in una singola funzione, cioè le loro posizioni e dimensioni possono dipendere l'una dall'altra, cosa che non puoi ottenere usando, ad esempio, il Stackwidget predefinito .

CustomMultiChildLayout(
  children: [
    // Widgets you want to layout in a customized manner
  ],
)

Ora, ci sono altri due passi che devi prendere prima di poter iniziare a preparare i tuoi figli:

  1. Ogni bambino a cui passi childrendeve essere un LayoutIde passi a quello il widget che in realtà vuoi mostrare come bambino LayoutId. Il idsarà identificare in modo univoco i widget, rendendoli accessibili quando si posa fuori:
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'),
    ),
  ],
)
  1. È necessario creare una MultiChildLayoutDelegatesottoclasse che gestisca la parte del layout. La documentazione qui sembra essere molto elaborata.
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;
}

Ora, tutta l'installazione è terminata e puoi iniziare a implementare il layout effettivo. Esistono tre metodi che è possibile utilizzare per questo:

  • hasChild, che consente di verificare se un particolare ID (ricordi LayoutId?) è stato passato a children, ovvero se è presente un figlio di quell'ID.

  • layoutChild, che devi chiamare per ogni ID , ogni bambino, fornito esattamente una volta e ti darà Sizequel figlio.

  • positionChild, che consente di modificare la posizione da Offset(0, 0)qualsiasi offset specificato.

Sento che il concetto dovrebbe essere abbastanza chiaro ora, motivo per cui illustrerò come implementare un delegato per l'esempio 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.
        ),
      );
    }
  }
}

Altri due esempi sono quello della documentazione (controllare la fase di preparazione 2 ) e un esempio reale che ho scritto qualche tempo fa per il feature_discoverypacchetto: MultiChildLayoutDelegateimplementazione e CustomMultiChildLayoutnel buildmetodo .

L'ultimo passaggio è l'override del shouldRelayoutmetodo , che controlla semplicemente se performLayoutdebba essere richiamato in un dato momento nel tempo confrontandolo con un vecchio delegato (facoltativamente puoi anche sovrascrivere getSize) e aggiungendo il delegato al tuo 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)
  ],
)

considerazioni

  • Ho usato 1e 2come ID in questo esempio, ma usare un enumè probabilmente il modo migliore per gestire gli ID se hai ID specifici.

  • È possibile passare Listenablea super(ad esempio super(relayout: animation)) se si desidera animare il processo di layout o attivarlo in base a un ascolto in generale.

CustomSingleChildLayout

La documentazione spiega molto bene quello che ho descritto sopra e qui vedrai anche perché ho detto che CustomSingleChildLayoutsarà molto ovvio dopo aver capito come CustomMultiChildLayoutfunziona:

CustomMultiChildLayout è appropriato quando esistono relazioni complesse tra dimensioni e posizionamento di più widget. Per controllare il layout di un singolo figlio, CustomSingleChildLayout è più appropriato.

Questo significa anche che l'utilizzo CustomSingleChildLayoutsegue gli stessi principi che ho descritto sopra, ma senza ID perché c'è un solo figlio.
Devi SingleChildLayoutDelegateinvece usare un , che ha diversi metodi per implementare il layout (hanno tutti un comportamento predefinito, quindi sono tecnicamente tutti opzionali da sovrascrivere ):

Tutto il resto è esattamente lo stesso (ricorda che non hai bisogno LayoutIde hai solo un bambino invece di children).


MultiChildRenderObjectWidget

Questo è ciò su cui CustomMultiChildLayoutsi basa.
L'uso di questo richiede una conoscenza ancora più approfondita di Flutter ed è ancora un po 'più complicato, ma è l'opzione migliore se si desidera una maggiore personalizzazione perché è anche di livello inferiore. Questo ha un grande vantaggio rispetto CustomMultiChildLayout(in generale, c'è un maggiore controllo):

CustomMultiChildLayout non può dimensionare base ai suoi figli (vedi il problema relativo a una migliore documentazione per il ragionamento ).

Non spiegherò come utilizzare MultiChildRenderObjectWidgetqui per ovvi motivi, ma se sei interessato, puoi dare un'occhiata mia presentazione alla sfida Flutter Clock dopo il 20 gennaio 2020, in cui utilizzo MultiChildRenderObjectWidgetampiamente: puoi anche leggere un articolo su questo , che dovrebbe spiegare un po 'di come funziona tutto.

Per ora puoi ricordartelo MultiChildRenderObjectWidget è ciò che rende CustomMultiChildLayoutpossibile e usarlo direttamente ti darà alcuni benefici come non doverlo usare LayoutIde poter accedere RenderObjectdirettamente ai dati dei genitori.

Fatto divertente

Ho scritto tutto il codice in testo semplice (nel campo di testo StackOverflow), quindi se ci sono errori, ti preghiamo di indicarmeli e li riparerò.


1
Wow. Risposta incredibile. Dovrebbe LayoutIdessere unico a livello globale o locale? a livello globale, ad esempio, i widget di tipo fratelli CustomMultiChildLayoutrichiedono di avere LayoutIdfigli distinti nei loro figli.
om-ha il

1
@ om-ha localmente: l'id verrà archiviato nei dati padre di LayoutId, il che significa che questi dati, l'id, saranno accessibili solo al genitore diretto :)
creativecreatorormaybenot

2
WOW! Sei il mio salvatore! Questo è ciò di cui sto parlando! ecco come dovrebbe essere la documentazione del flutter !! Non avrei mai potuto capire come queste classi funzionassero solo con la normale documentazione. GRAZIE MILLE!
Walter M,

1
Incredibile risposta davvero. CustomMultiChildLayoutè così utile in scenari in cui è necessario gruppo di auto-ridimensionamento più widget di testo all'interno di una Columndi Row's, per un esempio.
om-ha il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.