TL; 博士
如果沒有關于小部件的檔案,我如何知道小部件的布局規則(它將從其父級請求什么大小以及它將傳遞給其子級的約束是什么)?
問題詳情
我有這個非常基本的應用程式
void main() {
runApp(
Container(
color: Colors.red,
width: 20,
height: 20,
),
);
}
我原以為Container20 的寬度和高度,但我得到了一個Container填滿了整個螢屏。
閱讀此文章flutter.dev大概的了解的限制,其最后一部分所謂的“學習特定部件的布局規則”,他們提到了如何找到做這個createRenderObject方法,然后找到performLayout方法。
但是,此createRenderObject方法僅適用于 的子類RenderObjectWidget。例如,瀏覽Transform小部件的代碼,我發現createRenderObject它回傳一個RenderTransform,即 extends RenderProxyBox,它最終實作performLayout為:
@override
void performLayout() {
if (child != null) {
child!.layout(constraints, parentUsesSize: true);
size = child!.size;
} else {
size = computeSizeForNoChild(constraints);
}
}
我可以得出結論,Transform由于這一行,widget 最終將采用其子項的大小size = child!.size;。
但在Container上述情況下,是直接 extends StatelessWidget。我無法通過瀏覽其代碼找到方法performLayout和createRenderObject,我只能找到createElement,但我正在尋找RenderObject與容器關聯的渲染樹中的 ,而不是元素。
問題
所以問題是如何找到這個與無狀態小部件/有狀態小部件相關聯的渲染物件,以便知道這個小部件將給它的孩子的布局規則,并在這種情況下會跟隨他們自己?
uj5u.com熱心網友回復:
你有一定道理。我會說我的文章在這方面不夠精確。
小部件不需要創建RenderObject. 相反,它可以使用創建RenderObjects自己的其他小部件的組合。
如果一個小部件是其他小部件的組合,那么performLayout您可以簡單地查看該小部件的build方法來查看它在做什么,而不是查看它。在 a 的情況下Container,這是它的build方法:
Widget build(BuildContext context) {
Widget? current = child;
if (child == null && (constraints == null || !constraints!.isTight)) {
current = LimitedBox(
maxWidth: 0.0,
maxHeight: 0.0,
child: ConstrainedBox(constraints: const BoxConstraints.expand()),
);
}
if (alignment != null)
current = Align(alignment: alignment!, child: current);
final EdgeInsetsGeometry? effectivePadding = _paddingIncludingDecoration;
if (effectivePadding != null)
current = Padding(padding: effectivePadding, child: current);
if (color != null)
current = ColoredBox(color: color!, child: current);
if (clipBehavior != Clip.none) {
assert(decoration != null);
current = ClipPath(
clipper: _DecorationClipper(
textDirection: Directionality.maybeOf(context),
decoration: decoration!,
),
clipBehavior: clipBehavior,
child: current,
);
}
if (decoration != null)
current = DecoratedBox(decoration: decoration!, child: current);
if (foregroundDecoration != null) {
current = DecoratedBox(
decoration: foregroundDecoration!,
position: DecorationPosition.foreground,
child: current,
);
}
if (constraints != null)
current = ConstrainedBox(constraints: constraints!, child: current);
if (margin != null)
current = Padding(padding: margin!, child: current);
if (transform != null)
current = Transform(transform: transform!, alignment: transformAlignment, child: current);
return current!;
}
如您所見,它是根據其他小部件定義的。并且這些widget也可以根據其他widget等來定義。但是在某些時候,您將到達創建RenderObjects的小部件。
關于Container不是 20x20的原因,這是因為,正如文章所解釋的,尺寸是由父母設定的。所以Containers 的大小由Container的父級設定,在這種情況下是screen。并且螢屏總是強迫它的孩子占據所有可用空間,在這種情況下忽略了Container20x20 的愿望。這里的解決方法是給Container另一個父母。一種允許Container選擇自己的尺寸。例如,雙方Center并Align讓這種情況發生,這就是為什么你可以這樣做解決問題:
void main() {
runApp(
Center(
child: Container(
color: Colors.red,
width: 20,
height: 20,
),),);
}
至于為什么螢屏會強迫它的孩子占據所有可用空間:這正是 Flutter 創建者認為應該的方式。如果你深入研究 Flutter 的代碼,你會在那里找到它。但最好記住這個事實。
希望能幫助到你!
uj5u.com熱心網友回復:
您在這里缺少架構,我們需要使用Scaffold。喜歡
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: Container(
color: Colors.red,
width: 20,
height: 20,
),
)),
);
}
uj5u.com熱心網友回復:
嗯,不要太復雜了。這是我可以向您解釋的最簡單的事情,讓我們將應用程式分成 4 個不同的層。
- 應用程式 -> 可以
MaterialApp用來創建材質應用程式 - 小部件頁面 -> 您可以選擇使用
Stateless或StatefulWidget,這取決于您的需要。如果你需要動態的,你可以使用很多變化的狀態,StatefulWidget或者你可以用StatelessWidget. - Scaffold -> Widget 頁面必須回傳一個腳手架才能形成一個材質頁面,這里可以使用
Scaffold,可以添加appBar、fab、body、bottomNavigationBar等。 - 小部件 -> 小部件可以是任何東西,可以是腳手架 appBar 的 appBar,也可以是 ListView、GridView 或自定義小部件。
所以你的代碼必須是這樣的
/// This block is the first point of your application, this will run your application
void main() {
runApp(myApp());
}
/// Then you need an material app, this part should return your app
class MyApp extends StatelessWidget{
/// This is very important, both StatelessWidget / StatefullWidget
/// always having a build method. It's should returning a Widget. But in this case we will return an material application
@override
Widget build(BuildContext context){
return MaterialApp(
home: MyHome(),
),
}
}
class MyHome extends StatelessWidget{
/// This is home page, it's have Scaffold so the page will using, material guidelines.
@override
Widget build(BuildContext context){
return Scaffold(
body:Container(
color: Colors.red,
width: 20,
height: 20,
),
);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/334727.html
