Як використовувати CustomMultiChildLayout та CustomSingleChildLayout у Flutter


10

Може хтось із досвідом використання CustomSingleChildLayoutтаCustomMultiChildLayout занять може детально пояснити (на прикладах), як ними користуватися.

Я новачок у Flutter і намагаюся зрозуміти, як їх використовувати. Однак документація жахлива і незрозуміла. Я намагався шукати приклади в Інтернеті, але іншої документації немає.

Я був би вічно вдячний, якби ви могли допомогти.

Дякую!


Не могли б ви додати, для чого ви хочете їх використовувати?
Жоао Соарес

@ JoãoSoares Не турбуйся про це, оскільки я пишу обширну відповідь.
creativecreatorormaybenot

Великі очікування тоді!
Жоао Соарес

@ JoãoSoares Готово, повідомте мене, чи є виправлення.
creativecreatorormaybenot

@creativecreatorormaybenot Це було б дуже малоймовірно. Я вже бачив ваші відповіді. Чудова відповідь, як завжди.
Жоао Соарес

Відповіді:


20

Перш за все, хочу сказати, що я радий допомогти вам у цьому, оскільки я можу зрозуміти вашу боротьбу - є користь і для того, щоб розібратися в цьому самі (документація є приголомшливою).

Що CustomSingleChildLayoutбуде очевидно після того, як я вам пояснив CustomMultiChildLayout.

CustomMultiChildLayout

Суть цього віджета дозволяє вам розташувати дітей, які ви переходите до цього віджету, в одній функції, тобто їх положення та розміри можуть залежати один від одного, чого ви не можете досягти, наприклад, заздалегідь вбудований Stackвіджет.

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

Тепер є ще два кроки, які потрібно зробити, перш ніж почати викладати своїх дітей:

  1. Кожна дитина, якій ви переходите, 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'),
    ),
  ],
)
  1. Потрібно створити 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, що дозволяє перевірити, чи був переданий певний ідентифікатор (пам’ятаєте LayoutId?) children, тобто чи є дитина цього ідентифікатора.

  • layoutChild, яку потрібно зателефонувати на кожен ідентифікатор , кожну дитину за умови, що вказується рівно один раз, і це дасть тобі Sizeцю дитину.

  • 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методі .

Останнім кроком є ​​переосмислення shouldRelayoutметоду , який простий керує тим, чи performLayoutслід викликати повторно в будь-який момент часу, порівнюючи зі старим делегатом (необов'язково, ви також можете переопределити getSize) та додавши делегата до свого 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і 2як ідентифікатори в цьому прикладі, але використовуючиenum , мабуть, найкращий спосіб обробити ідентифікатори, якщо у вас є конкретні ідентифікатори.

  • Ви можете передати Listenableна super(наприклад super(relayout: animation)), якщо ви хочете анімувати процес компонування або запустити його на основі прослуховуваного в цілому.

CustomSingleChildLayout

Документація пояснює те, що я описав вище, дійсно добре, і тут ви також побачите, чому я сказав, що CustomSingleChildLayoutце буде дуже очевидно, зрозумівши, як CustomMultiChildLayoutпрацює:

CustomMultiChildLayout підходить, коли між розміром і розміщенням декількох віджетів є складні взаємозв'язки. Для управління компонуванням однієї дитини більш підходящим є CustomSingleChildLayout .

Це також означає, що використання CustomSingleChildLayoutтаких же принципів, як я описав вище, але без будь-яких ідентифікаторів, оскільки є лише одна дитина.
Вам потрібно використовувати SingleChildLayoutDelegateнатомість, який має різні способи реалізації макета (всі вони мають типову поведінку, тому їх технічно все необов'язково переосмислювати ):

  • getConstraintsForChild, що еквівалентно обмеженням, про які я перейшов layoutChildвище.

  • getPositionForChild, що еквівалентно positionChildвище.

Все інше точно так само (пам’ятайте, що вам не потрібно LayoutIdі мати тільки одну дитину замість children).


MultiChildRenderObjectWidget

Це те CustomMultiChildLayout, на чому будується.
Використання цього вимагає ще глибших знань про Flutter і знову трохи складніше, але це кращий варіант, якщо ви хочете більше налаштувати, оскільки це ще нижчий рівень. Це має одну головну перевагу перед CustomMultiChildLayout(як правило, більше контролю):

CustomMultiChildLayout не може розміром себе на основі своїх дітей (див питання про краще документації для міркувань ).

Я не буду пояснювати, як MultiChildRenderObjectWidgetтут користуватися з очевидних причин, але якщо вас цікавить, ви можете перевірити моє подання на виклик годинника Flutter після 20 січня 2020 року, в якому я MultiChildRenderObjectWidgetшироко використовую - ви також можете прочитати статтю про це , що має трохи пояснити, як все це працює.

Поки ви можете пам’ятати, що MultiChildRenderObjectWidgetсаме це стає CustomMultiChildLayoutможливим, а використання їх безпосередньо дасть вам корисні переваги, такі як відсутність використання LayoutIdта натомість можливість доступу до RenderObjectбатьківських даних безпосередньо.

Смішний факт

Я написав увесь код у простому тексті (у текстовому полі StackOverflow), тому, якщо є помилки, будь ласка, вкажіть їх на мене, і я їх виправлю.


1
Ого. Дивовижна відповідь. Чи має LayoutIdбути унікальним у глобальному чи локальному масштабі? В усьому світі, тобто, віджети такого типу братів та сестер CustomMultiChildLayoutпотребують різних LayoutIdдітей.
ом-га

1
@ om-ha Місцево - ідентифікатор буде зберігатися у батьківських даних LayoutId, що означає, що до цих даних, ідентифікатора, буде доступний лише прямий батько :)
creativecreatorormaybenot

2
ОЦЕ ТАК! Ти мій рятівник! ЦЕ Я ЧОМУ Я БУДУ РАЗОМ! ось якою має бути документація про загравання !! Я не міг би зрозуміти, як ці класи працювали лише зі звичайною документацією. ДУЖЕ ДЯКУЮ!
Вальтер М

1
Дивовижна відповідь дійсно. CustomMultiChildLayoutтак корисний в тих випадках , коли вам потрібно група автоматичної зміни розміру декількох віджетів тексту всередині Columnз Row«s, для прикладу.
ом-ха
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.