flutter-layout
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGoal
目标
Constructs robust, responsive Flutter user interfaces by composing layout widgets, managing constraints, and implementing adaptive design patterns. Assumes the target environment has the Flutter SDK installed and the user is familiar with Dart syntax and state management fundamentals.
通过组合布局组件、管理约束以及实现自适应设计模式,构建健壮、响应式的Flutter用户界面。本指南假设目标环境已安装Flutter SDK,且用户熟悉Dart语法和状态管理基础。
Instructions
使用说明
-
Determine Layout Strategy (Decision Logic) Analyze the UI requirements and select the appropriate base layout widgets using the following decision tree:
- Is the content strictly 1-Dimensional?
- Horizontal arrangement -> Use .
Row - Vertical arrangement -> Use .
Column
- Horizontal arrangement -> Use
- Does the content need to overlap (Z-axis)?
- Yes -> Use with
StackorPositionedchildren.Align
- Yes -> Use
- Does the content exceed the screen size?
- Yes, 1D list -> Use .
ListView - Yes, 2D grid -> Use .
GridView - Yes, custom scroll effects -> Use with Slivers.
CustomScrollView
- Yes, 1D list -> Use
- Does the layout need to adapt to screen size changes?
- Yes -> Use or
LayoutBuilder.MediaQuery
- Yes -> Use
- Is the content strictly 1-Dimensional?
-
Apply the Golden Rule of Constraints Enforce Flutter's core layout rule: Constraints go down. Sizes go up. Parent sets position. When a widget requires a specific size, ensure its parent allows it. Useto inject specific constraints, but remember it only adds to the parent's constraints.
ConstrainedBoxdart// Example: Forcing a specific size within a flexible parent Center( child: ConstrainedBox( constraints: const BoxConstraints( minWidth: 70, minHeight: 70, maxWidth: 150, maxHeight: 150, ), child: Container( color: Colors.blue, width: 1000, // Will be constrained to 150 (max) height: 10, // Will be constrained to 70 (min) ), ), ) -
Implement Adaptive Layouts For screens that must support both mobile and tablet/desktop form factors, implement ato branch the UI logic based on available width.
LayoutBuilderdartclass AdaptiveScreen extends StatelessWidget { const AdaptiveScreen({super.key}); Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth > 600) { return _buildWideLayout(); } else { return _buildNarrowLayout(); } }, ), ), ); } Widget _buildWideLayout() { return Row( children: [ const SizedBox(width: 250, child: Placeholder()), // Sidebar Container(width: 1, color: Colors.grey), // Divider const Expanded(child: Placeholder()), // Main Content ], ); } Widget _buildNarrowLayout() { return const Column( children: [ Expanded(child: Placeholder()), // Main Content ], ); } } -
Compose Flex Layouts (Rows and Columns) When usingor
Row, manage child sizing usingColumn(forces child to fill available space) orExpanded(allows child to be smaller than available space).FlexibledartRow( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ const Icon(Icons.star), Expanded( flex: 2, child: Container(color: Colors.red, height: 50), ), Flexible( flex: 1, child: Container(color: Colors.blue, height: 50), ), ], ) -
Gather Context STOP AND ASK THE USER: "What are the target devices (e.g., mobile, tablet, web) and specific breakpoint widths required for this layout?"
-
Validate-and-Fix: Handle Unbounded Constraints Verify that noor
Expandedwidgets are placed inside unbounded parents (likeFlexibleorListView). If a RenderFlex overflow occurs, implement the following fix:SingleChildScrollViewdart// INCORRECT: Expanded inside a scrollable view causes unbounded height errors. // SingleChildScrollView(child: Column(children: [Expanded(child: Container())])) // CORRECT: Use a bounded height or remove Expanded. // Alternatively, use CustomScrollView with SliverFillRemaining: CustomScrollView( slivers: [ SliverToBoxAdapter(child: HeaderWidget()), SliverFillRemaining( hasScrollBody: false, child: ExpandedContentWidget(), ), ], )
-
确定布局策略(决策逻辑) 分析UI需求,结合以下决策树选择合适的基础布局组件:
- 内容是否为严格的一维结构?
- 横向排列 -> 使用
Row - 纵向排列 -> 使用
Column
- 横向排列 -> 使用
- 内容需要层叠展示(Z轴)吗?
- 是 -> 使用,搭配
Stack或Positioned子组件Align
- 是 -> 使用
- 内容超出屏幕尺寸吗?
- 是,一维列表 -> 使用
ListView - 是,二维网格 -> 使用
GridView - 是,自定义滚动效果 -> 使用搭配Slivers的
CustomScrollView
- 是,一维列表 -> 使用
- 布局需要适配屏幕尺寸变化吗?
- 是 -> 使用或
LayoutBuilderMediaQuery
- 是 -> 使用
- 内容是否为严格的一维结构?
-
遵守约束黄金法则 遵循Flutter核心布局规则:约束向下传递,尺寸向上反馈,父组件决定位置。 当组件需要特定尺寸时,确保其父组件允许该尺寸。可使用添加特定约束,但请注意它只能在父组件约束基础上追加限制。
ConstrainedBoxdart// Example: Forcing a specific size within a flexible parent Center( child: ConstrainedBox( constraints: const BoxConstraints( minWidth: 70, minHeight: 70, maxWidth: 150, maxHeight: 150, ), child: Container( color: Colors.blue, width: 1000, // Will be constrained to 150 (max) height: 10, // Will be constrained to 70 (min) ), ), ) -
实现自适应布局 针对需要同时支持手机、平板/桌面设备的屏幕,通过根据可用宽度分支实现UI逻辑。
LayoutBuilderdartclass AdaptiveScreen extends StatelessWidget { const AdaptiveScreen({super.key}); Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth > 600) { return _buildWideLayout(); } else { return _buildNarrowLayout(); } }, ), ), ); } Widget _buildWideLayout() { return Row( children: [ const SizedBox(width: 250, child: Placeholder()), // Sidebar Container(width: 1, color: Colors.grey), // Divider const Expanded(child: Placeholder()), // Main Content ], ); } Widget _buildNarrowLayout() { return const Column( children: [ Expanded(child: Placeholder()), // Main Content ], ); } } -
组合弹性布局(Rows和Columns) 使用或
Row时,通过Column(强制子组件占满可用空间)或Expanded(允许子组件尺寸小于可用空间)管理子组件大小。FlexibledartRow( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ const Icon(Icons.star), Expanded( flex: 2, child: Container(color: Colors.red, height: 50), ), Flexible( flex: 1, child: Container(color: Colors.blue, height: 50), ), ], ) -
收集上下文信息 请暂停并询问用户: "本次布局的目标设备是哪些(例如手机、平板、网页)?需要的具体断点宽度是多少?"
-
验证与修复:处理无界约束问题 确认没有或
Expanded组件被放置在无界父容器内(比如Flexible或ListView)。如果出现RenderFlex溢出问题,可通过以下方案修复:SingleChildScrollViewdart// INCORRECT: Expanded inside a scrollable view causes unbounded height errors. // SingleChildScrollView(child: Column(children: [Expanded(child: Container())])) // CORRECT: Use a bounded height or remove Expanded. // Alternatively, use CustomScrollView with SliverFillRemaining: CustomScrollView( slivers: [ SliverToBoxAdapter(child: HeaderWidget()), SliverFillRemaining( hasScrollBody: false, child: ExpandedContentWidget(), ), ], )
Constraints
约束条件
- Always wrap top-level screen content in a to prevent overlap with system UI.
SafeArea - Never place an or
Expandedwidget inside a parent that provides unbounded constraints (e.g.,Flexible,SingleChildScrollView, orListViewinside a horizontally scrolling view).Row - Do not use solely for padding; use the
Containerwidget for better performance.Padding - Assume the user is using Material 3 (is default).
useMaterial3: true
- 始终将顶层屏幕内容包裹在内,避免与系统UI重叠。
SafeArea - 永远不要将或
Expanded组件放在提供无界约束的父组件内(例如Flexible、SingleChildScrollView,或者横向滚动视图内的ListView)。Row - 不要仅为了添加内边距就使用;使用
Container组件可获得更好的性能。Padding - 假设用户使用Material 3(默认配置为)。
useMaterial3: true