Cara menggunakan CustomMultiChildLayout & CustomSingleChildLayout di Flutter

10

Dapatkah seseorang yang berpengalaman dalam menggunakan CustomSingleChildLayoutdan CustomMultiChildLayoutkelas dapat menjelaskan secara detail (dengan contoh) tentang cara menggunakannya.

Saya baru mengenal Flutter dan berusaha memahami cara menggunakannya. Namun, dokumentasinya mengerikan dan tidak jelas. Saya mencoba menjelajahi internet untuk contoh, tetapi tidak ada dokumentasi lain.

Saya akan sangat berterima kasih jika Anda bisa membantu.

Terima kasih!

Walter M.
sumber
Bisakah Anda menambahkan untuk apa Anda ingin menggunakannya?
João Soares
@ JoãoSoares Jangan khawatir tentang ini karena saya menulis jawaban yang luas.
creativecreatorormaybenot
Harapan tinggi!
João Soares
@ JoãoSoares Selesai, beri tahu saya jika Anda memiliki koreksi.
creativecreatorormaybenot
@creativecreatorormaybenot Itu akan sangat tidak mungkin. Saya telah melihat jawaban Anda sebelumnya. Jawaban yang bagus, seperti biasa.
João Soares

Jawaban:

20

Pertama-tama, saya ingin mengatakan bahwa saya senang membantu Anda dengan ini karena saya dapat memahami perjuangan Anda - ada manfaat untuk mengatasinya sendiri (dokumentasi luar biasa).

Apa yang CustomSingleChildLayoutakan jelas setelah saya jelaskan CustomMultiChildLayoutkepada Anda.

CustomMultiChildLayout

Titik widget ini memungkinkan Anda untuk tata letak anak-anak Anda lulus untuk widget ini dalam satu fungsi, yaitu posisi dan ukuran mereka dapat bergantung satu sama lain, yang merupakan sesuatu yang Anda tidak dapat mencapai menggunakan misalnya yang prebuilt Stackwidget.

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

Sekarang, ada dua langkah lagi yang perlu Anda ambil sebelum mulai menata anak-anak Anda:

  1. Setiap anak yang Anda lewati childrenharuslah seorang LayoutIddan Anda lewati widget yang sebenarnya ingin Anda tunjukkan sebagai seorang anak LayoutId. Secara idunik akan mengidentifikasi widget Anda, membuatnya dapat diakses saat meletakkannya:
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. Anda perlu membuat MultiChildLayoutDelegatesubclass yang menangani bagian tata letak. Dokumentasi di sini tampaknya sangat rumit.
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;
}

Sekarang, semua pengaturan selesai dan Anda dapat mulai menerapkan tata letak yang sebenarnya. Ada tiga metode yang dapat Anda gunakan untuk itu:

  • hasChild, yang memungkinkan Anda memeriksa apakah id tertentu (ingat LayoutId?) diteruskan ke children, yaitu jika ada anak dari id itu.

  • layoutChild, yang perlu Anda panggil untuk setiap id , setiap anak, diberikan tepat satu kali dan itu akan memberi Anda Sizeanak itu.

  • positionChild, yang memungkinkan Anda untuk mengubah posisi dari Offset(0, 0)ke offset apa pun yang Anda tentukan.

Saya merasa konsepnya harus cukup jelas sekarang, itulah sebabnya saya akan menggambarkan bagaimana menerapkan delegasi sebagai contoh 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.
        ),
      );
    }
  }
}

Dua contoh lain adalah satu dari dokumentasi (periksa langkah persiapan 2 ) dan contoh dunia nyata yang saya tulis beberapa waktu lalu untuk feature_discoverypaket: MultiChildLayoutDelegateimplementasi dan CustomMultiChildLayoutdalam buildmetode .

Langkah terakhir adalah mengganti shouldRelayoutmetode , yang mengontrol sederhana apakah performLayoutharus dipanggil lagi pada suatu titik waktu tertentu dengan membandingkan dengan delegasi lama, (opsional Anda juga dapat menimpa getSize) dan menambahkan delegasi ke Anda 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)
  ],
)

Pertimbangan

  • Saya menggunakan 1dan 2sebagai id dalam contoh ini, tetapi menggunakan enummungkin merupakan cara terbaik untuk menangani id jika Anda memiliki id tertentu.

  • Anda dapat meneruskan Listenableke super(mis. super(relayout: animation)) Jika Anda ingin menghidupkan proses tata letak atau memicunya berdasarkan yang dapat didengarkan secara umum.

CustomSingleChildLayout

Dokumentasi menjelaskan apa yang saya jelaskan di atas dengan sangat baik dan di sini Anda juga akan melihat mengapa saya mengatakan itu CustomSingleChildLayoutakan sangat jelas setelah memahami cara CustomMultiChildLayoutkerjanya:

CustomMultiChildLayout sesuai ketika ada hubungan yang kompleks antara ukuran dan posisi beberapa widget. Untuk mengontrol tata letak satu anak, CustomSingleChildLayout lebih tepat.

Ini juga berarti bahwa menggunakan CustomSingleChildLayoutmengikuti prinsip yang sama yang saya jelaskan di atas, tetapi tanpa id karena hanya ada satu anak.
Anda harus menggunakan SingleChildLayoutDelegate, yang memiliki metode berbeda untuk menerapkan tata letak (semuanya memiliki perilaku default, sehingga secara teknis semuanya opsional untuk ditimpa ):

Semua yang lain persis sama (ingat bahwa Anda tidak perlu LayoutIddan hanya memiliki satu anak, bukan children).


MultiChildRenderObjectWidget

Inilah yang CustomMultiChildLayoutdibangun.
Menggunakan ini membutuhkan pengetahuan yang lebih dalam tentang Flutter dan sekali lagi sedikit lebih rumit, tetapi itu adalah pilihan yang lebih baik jika Anda ingin lebih banyak penyesuaian karena ini bahkan lebih rendah. Ini memiliki satu keunggulan utama dibandingkan CustomMultiChildLayout(umumnya, ada lebih banyak kontrol):

CustomMultiChildLayout tidak dapat mengukur sendiri berdasarkan anak-anaknya (lihat masalah tentang dokumentasi yang lebih baik untuk alasannya ).

Saya tidak akan menjelaskan cara menggunakan di MultiChildRenderObjectWidgetsini karena alasan yang jelas, tetapi jika Anda tertarik, Anda dapat memeriksa kiriman saya ke tantangan Flutter Clock setelah 20 Januari 2020, di mana saya menggunakan MultiChildRenderObjectWidgetsecara luas - Anda juga dapat membaca artikel tentang ini , yang seharusnya menjelaskan sedikit tentang bagaimana semua itu bekerja.

Untuk saat ini Anda dapat mengingat bahwa MultiChildRenderObjectWidgetitulah yang CustomMultiChildLayoutmemungkinkan dan menggunakannya secara langsung akan memberi Anda beberapa manfaat bagus seperti tidak harus menggunakan LayoutIddan sebagai gantinya dapat mengakses RenderObjectdata induk 's secara langsung.

Fakta yang menyenangkan

Saya menulis semua kode dalam teks biasa (dalam bidang teks StackOverflow), jadi jika ada kesalahan, harap tunjukkan kepada saya dan saya akan memperbaikinya.

creativecreatorormaybenot
sumber
1
Wow. Jawaban yang luar biasa. Haruskah LayoutIdmenjadi unik secara global atau lokal? global yaitu apakah widget saudara kandung CustomMultiChildLayoutmemerlukan memiliki yang berbeda LayoutIdpada anak-anak mereka.
om-ha
1
@ om-ha Secara lokal - id akan disimpan dalam data induk LayoutId, yang berarti bahwa data ini, id, hanya akan diakses oleh induk langsung :)
creativecreatorormaybenot
2
WOW! Kamu adalah penyelamatku! INI ADALAH APA YANG SAYA BICARA. beginilah seharusnya dokumentasi flutter !! Tidak mungkin saya bisa mengetahui bagaimana kelas-kelas ini bekerja hanya dengan dokumentasi normal. TERIMA KASIH BANYAK!
Walter M
1
Benar-benar jawaban yang luar biasa. CustomMultiChildLayoutsangat berguna dalam skenario di mana Anda perlu untuk kelompok auto-resize beberapa widget Teks dalam Columndari Row's, untuk contoh.
om-ha