Her şeyden önce, mücadelelerinizi anlayabildiğim için size yardımcı olmaktan mutluluk duyduğumu söylemek istiyorum - bunu kendiniz de çözmenin faydaları var (belgeler inanılmaz).
CustomSingleChildLayout
Size açıkladıktan sonra ne olacağı belli CustomMultiChildLayout
olacak.
Bu widget'ın amacı, bu widget'a ilettiğiniz çocukları tek bir işlevde düzenlemenize izin verir , yani konumları ve boyutları birbirine bağlı olabilir, bu da önceden oluşturulmuş widget'ı kullanarak elde edemeyeceğiniz bir şeydir Stack
.
CustomMultiChildLayout(
children: [
// Widgets you want to layout in a customized manner
],
)
Şimdi, çocuklarınızı düzenlemeye başlamadan önce atmanız gereken iki adım daha var :
- Geçtiğiniz her çocuğun bir çocuk
children
olması LayoutId
ve aslında çocuk olarak göstermek istediğiniz widget'ı geçirmeniz gerekir LayoutId
. Bu id
, widget'larınızı benzersiz bir şekilde tanımlar ve bunları düzenlerken erişilebilir hale getirir:
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'),
),
],
)
MultiChildLayoutDelegate
Düzen bölümünü işleyen bir alt sınıf oluşturmanız gerekir . Buradaki belgeler çok ayrıntılı görünüyor.
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;
}
Şimdi, tüm kurulum yapılır ve gerçek düzeni uygulamaya başlayabilirsiniz. Bunun için kullanabileceğiniz üç yöntem vardır:
hasChild
Hangi belirli olmadığını kontrol sağlayan id (hatırlamak LayoutId
?) Geçildi children
o id çocuğu varsa, yani.
layoutChild
her kimlik , her çocuk için tam olarak bir kez verilen ve size Size
o çocuğu verecektir .
positionChild
, konumu Offset(0, 0)
belirttiğiniz herhangi bir ofsete değiştirmenize olanak tanır .
Kavramın şimdi oldukça açık olması gerektiğini hissediyorum, bu yüzden örnek için bir temsilci nasıl uygulanacağını göstereceğim 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.
),
);
}
}
}
Diğer iki örnek belgeleri (çek hazırlama gelen biri de adım 2'de ) ve gerçek dünya Bir süre için cevap yazdım Örneğin feature_discovery
: paketinde MultiChildLayoutDelegate
uygulanmasını ve CustomMultiChildLayout
içinde build
yöntemle .
Son adım, eski bir delege ile karşılaştırarak herhangi bir zamanda tekrar çağrılıp çağrılmayacağını kontrol eden shouldRelayout
yöntemiperformLayout
geçersiz kılar (isteğe bağlı olarak da geçersiz kılabilirsiniz getSize
) ve delegeyi kendinize ekleyebilirsiniz 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)
],
)
hususlar
Ben 1
ve bu örnekte id s 2
olarak kullandım , ancak bir kullanmak muhtemelen belirli kimlikleri varsa kimlikleri işlemek için en iyi yoldur.enum
Bir geçebilir Listenable
için super
(örneğin super(relayout: animation)
) bunu genel olarak dinlenebilir dayalı düzen işlemini veya tetiği animasyon istiyorum.
Belgeler , yukarıda neyi iyi tanımladığımı açıklıyor ve burada, CustomSingleChildLayout
nasıl CustomMultiChildLayout
çalıştığını anladıktan sonra neden çok açık olacağını söylediğimi de göreceksiniz :
CustomMultiChildLayout , birden çok widget'ın boyutu ve konumlandırması arasında karmaşık ilişkiler olduğunda uygundur. Tek bir çocuğun düzenini kontrol etmek için CustomSingleChildLayout daha uygundur.
Bu aynı zamanda kullanımın CustomSingleChildLayout
yukarıda tarif ettiğim aynı ilkeleri izlediği, ancak herhangi bir kimliği olmadığı anlamına gelir, çünkü sadece tek bir çocuk vardır. Düzeni uygulamak için farklı yöntemlere sahip
bir SingleChildLayoutDelegate
bunun yerine kullanmanız gerekir (hepsinin varsayılan davranışı vardır, bu nedenle teknik olarak hepsi geçersiz kılmak için isteğe bağlıdır ):
Diğer her şey tamamen aynıdır ( LayoutId
bunun yerine ihtiyacınız olmadığını ve sadece tek bir çocuğunuz olduğunu unutmayın children
).
Bu CustomMultiChildLayout
üzerine inşa edilmiş.
Bunu kullanmak Flutter hakkında daha derin bir bilgi gerektirir ve yine biraz daha karmaşıktır, ancak daha düşük bir seviye olduğu için daha fazla özelleştirme istiyorsanız daha iyi bir seçenektir. Bunun büyük bir avantajı CustomMultiChildLayout
vardır (genellikle daha fazla kontrol vardır):
CustomMultiChildLayout
kendisini çocuklarına göre boyutlandıramaz ( akıl yürütme için daha iyi dokümantasyon konusuna bakın).
MultiChildRenderObjectWidget
Burada bariz nedenlerle nasıl kullanılacağını açıklamayacağım , ancak ilgileniyorsanız, 20 Ocak 2020'den sonra yaygın olarak kullandığım Flutter Clock mücadelesine gönderimi kontrol edebilirsiniz - bununla ilgili bir makaleMultiChildRenderObjectWidget
de okuyabilirsiniz , ve bunların hepsinin nasıl çalıştığını biraz açıklamalı.
Şimdilik bunu mümkün MultiChildRenderObjectWidget
kılan şeyleri hatırlayabilirsiniz CustomMultiChildLayout
ve doğrudan kullanmanız, kullanmamanız LayoutId
ve bunun yerine RenderObject
ana verilere doğrudan erişebilmeniz gibi bazı güzel faydalar sağlayacaktır .
Eğlenceli gerçek
Tüm kodu düz metinde (StackOverflow metin alanına) yazdım, bu yüzden hatalar varsa, lütfen bana işaret edin ve bunları düzeltirim.