web-dev-qa-db-fra.com

Comment utiliser CustomMultiChildLayout et CustomSingleChildLayout dans Flutter

Une personne expérimentée dans l'utilisation des classes CustomSingleChildLayout et CustomMultiChildLayout peut-elle expliquer en détail (avec des exemples) comment les utiliser?.

Je suis nouveau sur Flutter et j'essaie de comprendre comment les utiliser. Cependant, la documentation est horrible et n'est pas claire. J'ai essayé de parcourir Internet pour trouver des exemples, mais il n'y a pas d'autre documentation.

Je vous serais éternellement reconnaissant si vous pouviez nous aider.

Je vous remercie!

10
Walter M

Tout d'abord, je tiens à dire que je suis heureux de vous aider avec cela car je peux comprendre vos difficultés - il y a aussi des avantages à le découvrir par vous-même (la documentation est incroyable).

Ce que fait CustomSingleChildLayout sera évident après que je vous ai expliqué CustomMultiChildLayout.

CustomMultiChildLayout

Le point de ce widget vous permet de mettre en page les enfants que vous passez à ce widget dans une seule fonction, c'est-à-dire que leurs positions et tailles peuvent dépendre les unes des autres , ce qui est quelque chose que vous ne pouvez pas réaliser en utilisant par exemple le widget Stack prédéfini.

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

Maintenant, il y a deux autres étapes que vous devez suivre avant de commencer à disposer vos enfants:

  1. Chaque enfant que vous passez à children doit être un LayoutId et vous passez le widget que vous voulez réellement montrer comme enfant à ce LayoutId. Le id identifiera de manière unique vos widgets, les rendant accessibles lors de leur disposition:
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. Vous devez créer une sous-classe MultiChildLayoutDelegate qui gère la partie mise en page. La documentation ici semble être très élaborée.
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;
}

Maintenant, toute la configuration est terminée et vous pouvez commencer à implémenter la disposition réelle. Vous pouvez utiliser trois méthodes pour cela:

  • hasChild , qui vous permet de vérifier si un identifiant particulier (rappelez-vous LayoutId?) a été passé à children, c'est-à-dire si un enfant de cet id est présent.

  • layoutChild , que vous devez appeler pour chaque id , chaque enfant, à condition que exactement une fois et il vous donnera le Size de cet enfant.

  • positionChild , qui vous permet de changer la position de Offset(0, 0) en n'importe quel décalage que vous spécifiez.

Je pense que le concept devrait être assez clair maintenant, c'est pourquoi je vais illustrer comment implémenter un délégué pour l'exemple 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.
        ),
      );
    }
  }
}

Deux autres exemples sont celui de la documentation (vérifiez la préparation étape 2) et un monde réel exemple que j'ai écrit il y a quelque temps pour le feature_discovery package: MultiChildLayoutDelegate implémentation et CustomMultiChildLayout dans la méthode build .

La dernière étape remplace la méthode shouldRelayout , qui contrôle simplement si performLayout doit être appelée à nouveau à un moment donné en la comparant à un ancien délégué, (éventuellement vous pouvez également remplacer getSize ) et ajouter le délégué à votre 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)
  ],
)

Considérations

  • J'ai utilisé 1 Et 2 Comme id s dans cet exemple, mais en utilisant un enum est probablement la meilleure façon de gérer les identifiants si vous avez des identifiants spécifiques.

  • Vous pouvez passer un Listenable à super (par exemple super(relayout: animation)) si vous souhaitez animer le processus de mise en page ou le déclencher en fonction d'une écoute en général.

CustomSingleChildLayout

La documentation explique très bien ce que j'ai décrit ci-dessus et ici vous verrez aussi pourquoi j'ai dit que CustomSingleChildLayout sera très évident après avoir compris comment CustomMultiChildLayout fonctionne:

CustomMultiChildLayout est approprié lorsqu'il existe des relations complexes entre la taille et le positionnement de plusieurs widgets. Pour contrôler la disposition d'un seul enfant, CustomSingleChildLayout est plus approprié.

Cela signifie également que l'utilisation de CustomSingleChildLayout suit les mêmes principes que ceux décrits ci-dessus, mais sans aucun identifiant car il n'y a qu'un seul enfant.
Vous devez utiliser à la place un SingleChildLayoutDelegate , qui a différentes méthodes pour implémenter la mise en page (ils ont tous un comportement par défaut, ils sont donc techniquement tous facultatifs pour remplacer ):

Tout le reste est exactement le même (rappelez-vous que vous n'avez pas besoin de LayoutId et que vous n'avez qu'un seul enfant au lieu de children).


MultiChildRenderObjectWidget

C'est sur cela que CustomMultiChildLayout est construit.
Son utilisation nécessite des connaissances encore plus approfondies sur Flutter et est encore un peu plus compliquée, mais c'est la meilleure option si vous souhaitez plus de personnalisation car elle est encore de niveau inférieur. Cela a un avantage majeur sur CustomMultiChildLayout (généralement, il y a plus de contrôle):

CustomMultiChildLayout ne peut pas se dimensionner lui-même en fonction de ses enfants (voir problème concernant une meilleure documentation pour le raisonnement ).

Je ne vais pas expliquer comment utiliser MultiChildRenderObjectWidget ici pour des raisons évidentes, mais si vous êtes intéressé, vous pouvez consulter ma soumission au défi Flutter Clock après le 20 janvier 2020, dans lequel J'utilise beaucoup MultiChildRenderObjectWidget - vous pouvez également lire n article à ce sujet , ce qui devrait expliquer un peu comment tout cela fonctionne.

Pour l'instant, vous vous souvenez que MultiChildRenderObjectWidget est ce qui rend CustomMultiChildLayout possible et son utilisation directe vous offrira quelques avantages agréables comme ne pas avoir à utiliser LayoutId et à la place, pouvoir accéder à Les données parent de RenderObject directement.

Fait amusant

J'ai écrit tout le code en texte brut (dans le champ de texte StackOverflow), donc s'il y a des erreurs, veuillez me les signaler et je les corrigerai.

13