- 我的小部件的尺寸看起来不合适,怎么回事?
- 我只想将Widget放置在特定位置,但是没有任何属性可以控制它,为什么呢?
- 我一直看到诸如BoxConstraints,RenderBox和Size之类的术语。它们之间有什么关系?
- 对布局系统如何工作有一个大概的了解?
“两个阶段” 布局系统和约束
Example
- If *max(w|h) = min (w|h)*,that is *tightly* constrained.
- If *min(w|h) = 0*,we have a *loose* constraint.
- If *max(w|h) != infinite*,the constraint is *bounded.*
- If *max(w|h) = infinite*,the constraint is *unbounded.*
- If *min(w|h) = infinite*,is just said to be *infinite*
-
-
import 'package:flutter/material.dart';
GlobalKey _keyMyApp = GlobalKey();
GlobalKey _keyMaterialApp = GlobalKey();
GlobalKey _keyHomePage = GlobalKey();
GlobalKey _keyScaffold = GlobalKey();
GlobalKey _keyAppbar = GlobalKey();
GlobalKey _keyCenter = GlobalKey();
GlobalKey _keyFAB = GlobalKey();
GlobalKey _keyText = GlobalKey();
void printConstraint(String name,BoxConstraints c) {
print(
'CONSTRAINT of $name: min(w=${c.minWidth.toInt()},h=${c.minHeight.toInt()}) max(w=${c.maxWidth.toInt()},h=${c.maxHeight.toInt()})',);
}
void printSizes() {
printSize('MyApp',_keyMyApp);
printSize('MaterialApp',_keyMaterialApp);
printSize('HomePage',_keyHomePage);
printSize('Scaffold',_keyScaffold);
printSize('Appbar',_keyAppbar);
printSize('Center',_keyCenter);
printSize('Text',_keyText);
printSize('FAB',_keyFAB);
}
void printSize(String name,GlobalKey key) {
final RenderBox renderBox = key.currentContext.findRenderObject();
final size = renderBox.size;
print("SIZE of $name: w=${size.width.toInt()},h=${size.height.toInt()}");
}
void printPositions() {
printPosition('MyApp',_keyMyApp);
printPosition('MaterialApp',_keyMaterialApp);
printPosition('HomePage',_keyHomePage);
printPosition('Scaffold',_keyScaffold);
printPosition('Appbar',_keyAppbar);
printPosition('Center',_keyCenter);
printPosition('Text',_keyText);
printPosition('FAB',_keyFAB);
}
void printPosition(String name,GlobalKey key) {
final RenderBox renderBox = key.currentContext.findRenderObject();
final position = renderBox.localToGlobal(Offset.zero);
print("POSITION of $name: $position ");
}
void main() {
runApp(LayoutBuilder(
builder: (context,constraints) {
printConstraint('MyApp',constraints);
return MyApp();
},));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
key: _keyMyApp,builder: (context,constraints) {
printConstraint('MaterialApp',constraints);
return MaterialApp(
key: _keyMaterialApp,title: 'Flutter Demo',theme: ThemeData(
primarySwatch: Colors.blue,visualDensity: VisualDensity.adaptivePlatformDensity,),home: LayoutBuilder(
builder: (context,constraints) {
printConstraint('HomePage',constraints);
return HomePage(
key: _keyHomePage,title: 'Flutter Demo Home Page',);
},);
},);
}
}
class HomePage extends StatefulWidget {
HomePage({Key key,this.title}) : super(key: key);
final String title;
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
super.initState();
}
void _afterLayout(_) {
printSizes();
printPositions();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context,constraints) {
printConstraint('Scaffold',constraints);
return Scaffold(
backgroundColor: Colors.purple,key: _keyScaffold,appBar: AppBar(
key: _keyAppbar,title: Text(widget.title),body: LayoutBuilder(
builder: (context,constraints) {
printConstraint('Center',constraints);
return Center(
key: _keyCenter,child: LayoutBuilder(builder: (context,constraints) {
printConstraint('Text',constraints);
return Text(
'You have pushed the button this many times:',key: _keyText,style: TextStyle(color: Colors.white),);
}),);
},floatingActionButton: LayoutBuilder(
builder: (context,constraints) {
printConstraint('FAB',constraints);
return FloatingActionButton(
key: _keyFAB,onPressed: printSizes,tooltip: 'Increment',child: Icon(Icons.add),);
});
}
}
- Scaffold告知Center其约束,让其选择在 0 < width < 392 和 0 < height < 697 中选择。请注意,最大高度为759(屏幕最大高度)减去80(AppBar选择的高度)。
- Center转到其子组件“Text”,转发相同的约束。
- Text选择一个足以显示其数据的大小(279:16),然后回复Center。
- 借助手上的几何信息(大小),Center可以在其笛卡尔系统内正确定位文本。作为父母,Center有权选择其子组件位置,在这种情况下,它决定将其居中。
- 然后,Center为自己选择一个大小,而不是仅选择一个“足够”的大小(如“Text”一样),而是决定尽可能大,因此受到了限制。
- Scaffold收到Center所需的尺寸,并且流程继续向其最后一个孩子:FAB
- FAB收到约束,然后将其首选大小返回给Scaffold(56:56)
- 最后,Scaffold还具有将每个孩子都放置在其笛卡尔系统内所需的所有几何信息。
- Size信息继续沿渲染树传播。
- 每个小部件都使用此信息将每个孩子放置在笛卡尔系统内。
- Scaffold回复HomePage,HomePage回复MaterialApp,MaterialApp回复MyApp。直到最后再次到达Main。
- Main获取此“最终”窗口小部件,并将其最终绑定到屏幕中。
有趣的事情要记住
- 小部件不知道其在屏幕上的位置;它的父组件才知道。
- 小部件可以选择想要的大小,但必须根据其父级的限制。
- 约束向下传播,而大小向上传播。
- 尝试了解约束条件,它们可能在以后有用。