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 CustomSingleChildLayout
akan jelas setelah saya jelaskan CustomMultiChildLayout
kepada Anda.
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 Stack
widget.
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:
- Setiap anak yang Anda lewati
children
haruslah seorang LayoutId
dan Anda lewati widget yang sebenarnya ingin Anda tunjukkan sebagai seorang anak LayoutId
. Secara id
unik 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'),
),
],
)
- Anda perlu membuat
MultiChildLayoutDelegate
subclass 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 Size
anak 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_discovery
paket: MultiChildLayoutDelegate
implementasi dan CustomMultiChildLayout
dalam build
metode .
Langkah terakhir adalah mengganti shouldRelayout
metode , yang mengontrol sederhana apakah performLayout
harus 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 1
dan 2
sebagai id dalam contoh ini, tetapi menggunakan enum
mungkin merupakan cara terbaik untuk menangani id jika Anda memiliki id tertentu.
Anda dapat meneruskan Listenable
ke super
(mis. super(relayout: animation)
) Jika Anda ingin menghidupkan proses tata letak atau memicunya berdasarkan yang dapat didengarkan secara umum.
Dokumentasi menjelaskan apa yang saya jelaskan di atas dengan sangat baik dan di sini Anda juga akan melihat mengapa saya mengatakan itu CustomSingleChildLayout
akan sangat jelas setelah memahami cara CustomMultiChildLayout
kerjanya:
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 CustomSingleChildLayout
mengikuti 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 LayoutId
dan hanya memiliki satu anak, bukan children
).
Inilah yang CustomMultiChildLayout
dibangun.
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 MultiChildRenderObjectWidget
sini 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 MultiChildRenderObjectWidget
secara luas - Anda juga dapat membaca artikel tentang ini , yang seharusnya menjelaskan sedikit tentang bagaimana semua itu bekerja.
Untuk saat ini Anda dapat mengingat bahwa MultiChildRenderObjectWidget
itulah yang CustomMultiChildLayout
memungkinkan dan menggunakannya secara langsung akan memberi Anda beberapa manfaat bagus seperti tidak harus menggunakan LayoutId
dan sebagai gantinya dapat mengakses RenderObject
data 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.