Flutter 中的布局概念
在 Flutter 中,布局是指将组件放置到屏幕上的过程。Flutter 的布局系统基于一系列的 Widget 类,这些类可以嵌套并组合成复杂的用户界面。Flutter 提供了多种内置的布局控件,如 Column、Row、Stack 等,它们能够帮助开发者轻松实现各种布局需求。
基础布局控件
Column - 垂直布局
Column 是一种垂直排列子元素的布局方式。它的子元素会从上到下依次排列。
// www.javascriptcn.com code example
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Column 布局示例')),
body: Column(
children: [
Container(color: Colors.red, height: 50),
Container(color: Colors.green, height: 50),
Container(color: Colors.blue, height: 50),
],
),
),
);
}
}Row - 水平布局
Row 是一种水平排列子元素的布局方式。它的子元素会从左到右依次排列。
// www.javascriptcn.com code example
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Row 布局示例')),
body: Row(
children: [
Container(color: Colors.red, width: 50),
Container(color: Colors.green, width: 50),
Container(color: Colors.blue, width: 50),
],
),
),
);
}
}Stack - 层叠布局
Stack 允许子元素重叠在一起。通过使用 Positioned 控件,可以控制每个子元素的具体位置。
// www.javascriptcn.com code example
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Stack 布局示例')),
body: Stack(
children: [
Positioned(top: 10, left: 10, child: Container(width: 50, height: 50, color: Colors.red)),
Positioned(top: 30, left: 30, child: Container(width: 50, height: 50, color: Colors.green)),
Positioned(top: 50, left: 50, child: Container(width: 50, height: 50, color: Colors.blue)),
],
),
),
);
}
}Flex 布局
Flex 布局是一种更灵活的布局方式,它允许子元素根据可用空间自动调整大小。
Expanded - 扩展子元素
Expanded 可以让其子元素占据剩余的空间。通常与 Row 或 Column 结合使用。
// www.javascriptcn.com code example
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Expanded 布局示例')),
body: Row(
children: [
Container(color: Colors.red, width: 50),
Expanded(child: Container(color: Colors.green)),
Container(color: Colors.blue, width: 50),
],
),
),
);
}
}Flexible - 灵活子元素
Flexible 和 Expanded 类似,但它允许子元素按比例分配剩余空间。
// www.javascriptcn.com code example
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Flexible 布局示例')),
body: Row(
children: [
Flexible(flex: 2, child: Container(color: Colors.red)),
Flexible(flex: 1, child: Container(color: Colors.green)),
Flexible(flex: 3, child: Container(color: Colors.blue)),
],
),
),
);
}
}自定义布局
除了使用内置的布局控件外,Flutter 还提供了自定义布局的方式,例如 CustomSingleChildLayout 和 CustomMultiChildLayout。这些控件允许开发者根据需要实现复杂的布局逻辑。
CustomSingleChildLayout
CustomSingleChildLayout 用于单个子元素的复杂布局。
// www.javascriptcn.com code example
import 'package:flutter/material.dart';
class MySingleChildLayoutPage extends StatefulWidget {
@override
_MySingleChildLayoutPageState createState() => _MySingleChildLayoutPageState();
}
class _MySingleChildLayoutPageState extends State<MySingleChildLayoutPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('CustomSingleChildLayout 示例')),
body: CustomSingleChildLayout(
delegate: MySingleChildLayoutDelegate(),
child: Container(color: Colors.blue, width: 100, height: 100),
),
);
}
}
class MySingleChildLayoutDelegate extends SingleChildLayoutDelegate {
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return BoxConstraints.tight(Size.square(100));
}
@override
Offset getPositionForChild(Size size, Size childSize) {
return Offset((size.width - childSize.width) / 2, (size.height - childSize.height) / 2);
}
@override
bool shouldRelayout(covariant SingleChildLayoutDelegate oldDelegate) {
return false;
}
}
void main() {
runApp(MaterialApp(home: MySingleChildLayoutPage()));
}CustomMultiChildLayout
CustomMultiChildLayout 用于多个子元素的复杂布局。
// www.javascriptcn.com code example
import 'package:flutter/material.dart';
class MyMultiChildLayoutPage extends StatefulWidget {
@override
_MyMultiChildLayoutPageState createState() => _MyMultiChildLayoutPageState();
}
class _MyMultiChildLayoutPageState extends State<MyMultiChildLayoutPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('CustomMultiChildLayout 示例')),
body: CustomMultiChildLayout(
delegate: MyMultiChildLayoutDelegate(),
children: [
LayoutId(id: 'red', child: Container(color: Colors.red, width: 50, height: 50)),
LayoutId(id: 'green', child: Container(color: Colors.green, width: 50, height: 50)),
LayoutId(id: 'blue', child: Container(color: Colors.blue, width: 50, height: 50)),
],
),
);
}
}
class MyMultiChildLayoutDelegate extends MultiChildLayoutDelegate {
@override
void performLayout(Size size) {
if (hasChild('red')) {
layoutChild('red', BoxConstraints.tight(Size.square(50)));
positionChild('red', Offset((size.width - 50) / 2, (size.height - 50) / 4));
}
if (hasChild('green')) {
layoutChild('green', BoxConstraints.tight(Size.square(50)));
positionChild('green', Offset((size.width - 50) / 2, (size.height - 50) / 2));
}
if (hasChild('blue')) {
layoutChild('blue', BoxConstraints.tight(Size.square(50)));
positionChild('blue', Offset((size.width - 50) / 2, (size.height - 50) * 3 / 4));
}
}
@override
bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) {
return false;
}
}
void main() {
runApp(MaterialApp(home: MyMultiChildLayoutPage()));
}以上介绍了 Flutter 中的一些基础和进阶的布局方法。理解这些布局控件的使用,可以帮助开发者构建出更加美观且功能强大的用户界面。