Flutter 中的布局
Flutter 布局的核心机制是 widgets。在 Flutter 中,几乎所有东西都是 widget —— 甚至布局模型都是 widgets。你在 Flutter 应用程序中看到的图像,图标和文本都是 widgets。此外不能直接看到的也是 widgets,例如用来排列、限制和对齐可见 widgets 的行、列和网格。
The core of Flutter’s layout mechanism is widgets. In Flutter, almost everything is a widget—even layout models are widgets. The images, icons, and text that you see in a Flutter app are all widgets. But things you don’t see are also widgets, such as the rows, columns, and grids that arrange, constrain, and align the visible widgets.
你可以通过组合 widgets 来构建更复杂的 widgets 来创建布局。比如,下面第一个截图上有 3 个图标,每个图标下面都有一个标签:
You create a layout by composing widgets to build more complex widgets. For example, the first screenshot below shows 3 icons with a label under each one:


第二个截图显示了可视布局,可以看到有一排三列,其中每列包含一个图标和一个标签。
The second screenshot displays the visual layout, showing a row of 3 columns where each column contains an icon and a label.
以下是这个 UI 的 widget 树形图:
Here’s a diagram of the widget tree for this UI:
图上大部分应该和你预想的一样,但你可能会疑惑 containers(图上粉色显示的)是什么。
Container
是一个 widget,允许你自定义其子 widget。举几个例子,如果要添加 padding、margin、边框或背景颜色,你就可以用上 Container
了。
Most of this should look as you might expect, but you might be wondering
about the containers (shown in pink). Container
is a widget class
that allows you to customize its child widget. Use a Container
when
you want to add padding, margins, borders, or background color,
to name some of its capabilities.
在这个例子中,每个 Text
widget 都被放在一个 Container
以添加 padding。整个 Row
也被放在一个 Container
中,以便添加 padding。
In this example, each Text
widget is placed in a Container
to add margins. The entire Row
is also placed in a
Container
to add padding around the row.
这个例子其余部分的 UI 由属性控制。通过 Icon
的 color
属性来设置它的颜色,通过 Text.style
属性来设置文字的字体、颜色、字重等等。列和行有一些属性可以让你指定子项垂直或水平的对齐方式以及子项应占用的空间大小。
The rest of the UI in this example is controlled by properties.
Set an Icon
’s color using its color
property.
Use the Text.style
property to set the font, its color, weight, and so on.
Columns and rows have properties that allow you to specify how their
children are aligned vertically or horizontally, and how much space
the children should occupy.
布局 widget
Lay out a widget
如何在 Flutter 中布局单个 widget?本节将介绍如何创建和显示单个 widget。本节还包括一个简单的 Hello World app 的完整代码。
How do you lay out a single widget in Flutter? This section shows you how to create and display a simple widget. It also shows the entire code for a simple Hello World app.
在 Flutter 中,只需几步就可以在屏幕上显示文本、图标或图像。
In Flutter, it takes only a few steps to put text, an icon, or an image on the screen.
1. 选择一个布局 widget
1. Select a layout widget
根据你想要对齐或限制可见 widget 的方式从各种 layout widgets 中进行选择,因为这些特性通常会传递它所给包含的 widget。
Choose from a variety of layout widgets based on how you want to align or constrain the visible widget, as these characteristics are typically passed on to the contained widget.
本例使用将其内容水平和垂直居中的 Center
。
This example uses Center
which centers its content
horizontally and vertically.
2. 创建一个可见 widget
2. Create a visible widget
举个例子,创建一个 Text
widget:
For example, create a Text
widget:
Text('Hello World'),
创建一个 Image
widget:
Create an Image
widget:
Image.asset( 'images/lake.jpg', fit: BoxFit.cover, ),
创建一个 Icon
widget:
Create an Icon
widget:
Icon( Icons.star, color: Colors.red[500], ),
3. 将可见 widget 添加到布局 widget
3. Add the visible widget to the layout widget
所有布局 widgets 都具有以下任一项:
All layout widgets have either of the following:
-
一个
child
属性,如果它们只包含一个子项 —— 例如Center
和Container
A
child
property if they take a single child—for example,Center
orContainer
-
一个
children
属性,如果它们包含多个子项 —— 例如Row
、Column
、ListView
和Stack
A
children
property if they take a list of widgets—for example,Row
,Column
,ListView
, orStack
.
将 Text
widget 添加进 Center
widget:
Add the Text
widget to the Center
widget:
const Center( child: Text('Hello World'), ),
4. 将布局 widget 添加到页面
4. Add the layout widget to the page
一个 Flutter app 本身就是一个 widget,大多数 widgets 都有一个 build()
方法,在 app 的 build()
方法中实例化和返回一个 widget 会让它显示出来。
A Flutter app is itself a widget, and most widgets have a build()
method. Instantiating and returning a widget in the app’s build()
method
displays the widget.
对于 Material
app,你可以使用 Scaffold
widget,它提供默认的 banner 背景颜色,还有用于添加抽屉、提示条和底部列表弹窗的 API。你可以将 Center
widget 直接添加到主页 body
的属性中。
For a Material
app, you can use a Scaffold
widget;
it provides a default banner, background color,
and has API for adding drawers, snack bars, and bottom sheets.
Then you can add the Center
widget directly to the body
property for the home page.
class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter layout demo', home: Scaffold( appBar: AppBar( title: const Text('Flutter layout demo'), ), body: const Center( child: Text('Hello World'), ), ), ); } }
非 Material apps
Non-Material apps
对于非 Material app,你可以将 Center
widget 添加到 app 的 build()
方法里:
For a non-Material app, you can add the Center
widget to the app’s
build()
method:
class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return Container( decoration: const BoxDecoration(color: Colors.white), child: const Center( child: Text( 'Hello World', textDirection: TextDirection.ltr, style: TextStyle( fontSize: 32, color: Colors.black87, ), ), ), ); } }
默认情况下,非 Material app 不包含 AppBar
、标题和背景颜色。如果你希望在非 Material app 中使用这些功能,则必须自己构建它们。以上 app 将背景颜色更改为白色,将文本更改为深灰色来模拟一个 Material app。
By default a non-Material app doesn’t include an AppBar
, title,
or background color. If you want these features in a non-Material app,
you have to build them yourself. This app changes the background
color to white and the text to dark grey to mimic a Material app.
完成! 启动这个 app,你应该能看到 Hello World。
That’s it! When you run the app, you should see Hello World.
App 源码:
App source code:

横向或纵向布局多个 widgets
Lay out multiple widgets vertically and horizontally
最常见的布局模式之一是垂直或水平 widgets。你可以使用 Row widget 水平排列 widgets,使用 Column widget 垂直排列 widgets。
One of the most common layout patterns is to arrange
widgets vertically or horizontally. You can use a
Row
widget to arrange widgets horizontally,
and a Column
widget to arrange widgets vertically.
要在 Flutter 中创建行或列,可以将子 widgets 列表添加到
Row
或 Column
widget 中。反过来,每个子项本身可以是一行或一列,依此类推。以下示例演示了如何在行或列中嵌套行或列。
To create a row or column in Flutter, you add a list of children
widgets to a Row
or Column
widget. In turn,
each child can itself be a row or column, and so on.
The following example shows how it is possible to nest rows or
columns inside of rows or columns.
这个布局被组织为 Row
。这一行包含两个子项:左侧的列和右侧的图像:
This layout is organized as a Row
. The row contains two children:
a column on the left, and an image on the right:
左侧列的 widget 树嵌套着行和列。
The left column’s widget tree nests rows and columns.
你将在 嵌套行和列 中实现蛋糕介绍示例的一些布局代码。
You’ll implement some of Pavlova’s layout code in Nesting rows and columns.
对齐 widgets
Aligning widgets
你可以使用 mainAxisAlignment
和 crossAxisAlignment
属性控制行或列如何对齐其子项。对于一行来说,主轴水平延伸,交叉轴垂直延伸。对于一列来说,主轴垂直延伸,交叉轴水平延伸。
You control how a row or column aligns its children using the
mainAxisAlignment
and crossAxisAlignment
properties.
For a row, the main axis runs horizontally and the cross axis runs
vertically. For a column, the main axis runs vertically and the cross
axis runs horizontally.


MainAxisAlignment
和 CrossAxisAlignment
这两个枚举提供了很多用于控制对齐的常量。
The MainAxisAlignment
and CrossAxisAlignment
enums offer a variety of constants for controlling alignment.
在以下示例中,3 个图像每个都是是 100 像素宽。渲染框(在本例中是整个屏幕)宽度超过 300 像素,因此设置主轴对齐方式为 spaceEvenly
会将空余空间在每个图像之间、之前和之后均匀地划分。
In the following example, each of the 3 images is 100 pixels wide.
The render box (in this case, the entire screen)
is more than 300 pixels wide, so setting the main axis
alignment to spaceEvenly
divides the free horizontal
space evenly between, before, and after each image.
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('images/pic1.jpg'),
Image.asset('images/pic2.jpg'),
Image.asset('images/pic3.jpg'),
],
);
列的工作方式与行的工作方式相同。以下示例展示了包含 3 个图像的列,每个图像的高度为 100 像素。渲染框(在本例中是整个屏幕)高度超过 300 像素,因此设置主轴对齐方式为 spaceEvenly
会将空余空间在每个图像之间、之上和之下均匀地划分。
Columns work the same way as rows. The following example shows a column
of 3 images, each is 100 pixels high. The height of the render box
(in this case, the entire screen) is more than 300 pixels, so
setting the main axis alignment to spaceEvenly
divides the free vertical
space evenly between, above, and below each image.
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('images/pic1.jpg'),
Image.asset('images/pic2.jpg'),
Image.asset('images/pic3.jpg'),
],
);
App 源码: row_column
App source: row_column

调整 widgets 大小
Sizing widgets
当某个布局太大而超出屏幕时,受影响的边缘会出现黄色和黑色条纹图案。这里有一个行太宽的 例子:
When a layout is too large to fit a device, a yellow and black striped pattern appears along the affected edge. Here is an example of a row that is too wide:
通过使用 Expanded
widget,可以调整 widgets 的大小以适合行或列。要修复上一个图像行对其渲染框来说太宽的示例,可以用 Expanded
widget 把每个图像包起来。
Widgets can be sized to fit within a row or column by using the
Expanded
widget. To fix the previous example where the
row of images is too wide for its render box,
wrap each image with an Expanded
widget.
Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Image.asset('images/pic1.jpg'), ), Expanded( child: Image.asset('images/pic2.jpg'), ), Expanded( child: Image.asset('images/pic3.jpg'), ), ], );
也许你想要一个 widget 占用的空间是兄弟项的两倍。为了达到这个效果,可以使用 Expanded
widget 的 flex
属性,这是一个用来确定 widget 的弹性系数的整数。默认的弹性系数为 1,以下代码将中间图像的弹性系数设置为 2:
Perhaps you want a widget to occupy twice as much space as its
siblings. For this, use the Expanded
widget flex
property,
an integer that determines the flex factor for a widget.
The default flex factor is 1. The following code sets
the flex factor of the middle image to 2:
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset('images/pic1.jpg'),
),
Expanded(
flex: 2,
child: Image.asset('images/pic2.jpg'),
),
Expanded(
child: Image.asset('images/pic3.jpg'),
),
],
);
组合 widgets
Packing widgets
默认情况下,行或列沿其主轴会占用尽可能多的空间,但如果要将子项紧密组合在一起,请将其 mainAxisSize
设置为 MainAxisSize.min
。以下示例使用此属性将星形图标组合在一起。
By default, a row or column occupies as much space along its main axis
as possible, but if you want to pack the children closely together,
set its mainAxisSize
to MainAxisSize.min
. The following example
uses this property to pack the star icons together.
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
const Icon(Icons.star, color: Colors.black),
const Icon(Icons.star, color: Colors.black),
],
)
嵌套行和列
Nesting rows and columns
布局框架允许你根据需要在行和列内嵌套行和列。让我们看看以下布局的概述部分的代码:
The layout framework allows you to nest rows and columns inside of rows and columns as deeply as you need. Let’s look at the code for the outlined section of the following layout:
概述的部分实现为两行,评级一行包含五颗星和评论的数量,图标一行包含由图标与文本组成的三列。
The outlined section is implemented as two rows. The ratings row contains five stars and the number of reviews. The icons row contains three columns of icons and text.
以下是评级行的 widget 树形图:
The widget tree for the ratings row:
ratings
变量创建了一个行,其中包含较小的由 5 个星形图标和文本组成的一行:
The ratings
variable creates a row containing a smaller row
of 5 star icons, and text:
var stars = Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
const Icon(Icons.star, color: Colors.black),
const Icon(Icons.star, color: Colors.black),
],
);
final ratings = Container(
padding: const EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
stars,
const Text(
'170 Reviews',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 20,
),
),
],
),
);
评级行下方的图标行包含 3 列,每列包含一个图标和两行文本,你可以在其 widget 树中看到:
The icons row, below the ratings row, contains 3 columns; each column contains an icon and two lines of text, as you can see in its widget tree:
iconList
变量定义了图标行:
The iconList
variable defines the icons row:
const descTextStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 18,
height: 2,
);
// DefaultTextStyle.merge() allows you to create a default text
// style that is inherited by its child and all subsequent children.
final iconList = DefaultTextStyle.merge(
style: descTextStyle,
child: Container(
padding: const EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Icon(Icons.kitchen, color: Colors.green[500]),
const Text('PREP:'),
const Text('25 min'),
],
),
Column(
children: [
Icon(Icons.timer, color: Colors.green[500]),
const Text('COOK:'),
const Text('1 hr'),
],
),
Column(
children: [
Icon(Icons.restaurant, color: Colors.green[500]),
const Text('FEEDS:'),
const Text('4-6'),
],
),
],
),
),
);
leftColumn
变量包含评级和图标行,以及蛋糕介绍的标题和文本:
The leftColumn
variable contains the ratings and icons rows,
as well as the title and text that describes the Pavlova:
final leftColumn = Container(
padding: const EdgeInsets.fromLTRB(20, 30, 20, 20),
child: Column(
children: [
titleText,
subTitle,
ratings,
iconList,
],
),
);
左列放置在 Container
中以限制其宽度。最后,UI 由 Card
内的整行(包含左列和图像)构成。
The left column is placed in a SizedBox
to constrain its width.
Finally, the UI is constructed with the entire row (containing the
left column and the image) inside a Card
.
蛋糕图片 来自 Pixabay 网站。你可以使用 Image.network()
从网络上引用图像,但是在本例图像将保存到项目中的一个图像目录中,添加到 pubspec 文件,并使用 Images.asset()
访问。更多信息可以查看文档中关于 添加资源和图片 这一章。
The Pavlova image is from Pixabay.
You can embed an image from the net using Image.network()
but,
for this example, the image is saved to an images directory in the project,
added to the pubspec file, and accessed using Images.asset()
.
For more information, see Adding assets and images.
body: Center( child: Container( margin: const EdgeInsets.fromLTRB(0, 40, 0, 30), height: 600, child: Card( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 440, child: leftColumn, ), mainImage, ], ), ), ), ),
App 源码: pavlova
App source: pavlova
通用布局 widgets
Common layout widgets
Flutter 有一个丰富的布局 widget 仓库,里面有很多经常会用到的布局 widget。目的是为了让你更快的上手,而不是被一个完整的列表吓跑。关于其他有用的 widget 的信息,可以参考 Widget 目录,或者使用 API 参考文档 中的搜索框。而且,API 文档中的 widget 页面中经常会给出一些关于相似的 widget 哪个会更适合你的建议。
Flutter has a rich library of layout widgets. Here are a few of those most commonly used. The intent is to get you up and running as quickly as possible, rather than overwhelm you with a complete list. For information on other available widgets, refer to the Widget catalog, or use the Search box in the API reference docs. Also, the widget pages in the API docs often make suggestions about similar widgets that might better suit your needs.
下面的 widget 会分为两类:widgets 库 中的标准 widgets 和 Material 库 中的 widgets。任何 app 都可以使用 widget 库,但是 Material 库中的组件只能在 Material app 中使用。
The following widgets fall into two categories: standard widgets from the widgets library, and specialized widgets from the Material library. Any app can use the widgets library but only Material apps can use the Material Components library.
标准 widgets
Standard widgets
-
Container
:向 widget 增加 padding、margins、borders、background color 或者其他的“装饰”。Container
: Adds padding, margins, borders, background color, or other decorations to a widget. -
GridView
:将 widget 展示为一个可滚动的网格。GridView
: Lays widgets out as a scrollable grid. -
ListView
:将 widget 展示为一个可滚动的列表。ListView
: Lays widgets out as a scrollable list. -
Stack
:将 widget 覆盖在另一个的上面。Stack
: Overlaps a widget on top of another.
Material widgets
-
Card
:将相关信息整理到一个有圆角和阴影的盒子中。Card
: Organizes related info into a box with rounded corners and a drop shadow. -
ListTile
:将最多三行的文本、可选的导语以及后面的图标组织在一行中。ListTile
: Organizes up to 3 lines of text, and optional leading and trailing icons, into a row.
Container
许多布局都可以随意的用 Container
,它可以将使用了 padding 或者增加了 borders/margins 的 widget 分开。你可以通过将整个布局放到一个 Container
中,并且改变它的背景色或者图片,来改变设备的背景。
Many layouts make liberal use of Container
s to separate
widgets using padding, or to add borders or margins.
You can change the device’s background by placing the
entire layout into a Container
and changing its background
color or image.
摘要 (Container)
Summary (Container)
-
增加 padding、margins、borders
Add padding, margins, borders
-
改变背景色或者图片
Change background color or image
-
只包含一个子 widget,但是这个子 widget 可以是行、列或者是 widget 树的根 widget
Contains a single child widget, but that child can be a Row, Column, or even the root of a widget tree

示例 (Container)
Examples (Container)
这个布局包含一个有两行的列,每行有两张图片。
Container
用来将列的背景色变为浅灰色。
This layout consists of a column with two rows, each containing
2 images. A Container
is used to change the background color
of the column to a lighter grey.
Widget _buildImageColumn() {
return Container(
decoration: const BoxDecoration(
color: Colors.black26,
),
child: Column(
children: [
_buildImageRow(1),
_buildImageRow(3),
],
),
);
}

Container
还用来为每个图片添加圆角和外边距:
A Container
is also used to add a rounded border and margins
to each image:
Widget _buildDecoratedImage(int imageIndex) => Expanded(
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 10, color: Colors.black38),
borderRadius: const BorderRadius.all(Radius.circular(8)),
),
margin: const EdgeInsets.all(4),
child: Image.asset('images/pic$imageIndex.jpg'),
),
);
Widget _buildImageRow(int imageIndex) => Row(
children: [
_buildDecoratedImage(imageIndex),
_buildDecoratedImage(imageIndex + 1),
],
);
你可以在 布局构建教程 和 Flutter Gallery
中可以发现更多关于 Container
的例子。
You can find more Container
examples in the tutorial
and the Flutter Gallery (running app, repo).
App 源码: container
App source: container
GridView
使用 GridView
将 widget 作为二维列表展示。
GridView
提供两个预制的列表,或者你可以自定义网格。当 GridView
检测到内容太长而无法适应渲染盒时,它就会自动支持滚动。
Use GridView
to lay widgets out as a two-dimensional
list. GridView
provides two pre-fabricated lists,
or you can build your own custom grid. When a GridView
detects that its contents are too long to fit the render box,
it automatically scrolls.
摘要 (GridView)
Summary (GridView)
-
在网格中使用 widget
Lays widgets out in a grid
-
当列的内容超出渲染容器的时候,它会自动支持滚动。
Detects when the column content exceeds the render box and automatically provides scrolling
-
创建自定义的网格,或者使用下面提供的网格的其中一个:
Build your own custom grid, or use one of the provided grids:
-
GridView.count
允许你制定列的数量GridView.count
allows you to specify the number of columns -
GridView.extent
允许你制定单元格的最大宽度GridView.extent
allows you to specify the maximum pixel width of a tile
-
示例 (GridView)
Examples (GridView)
使用 GridView.extent
创建一个最大宽度为 150 像素的网格。
Uses GridView.extent
to create a grid with tiles a maximum
150 pixels wide.
App 源码: grid_and_list
App source: grid_and_list
使用 GridView.count
创建一个网格,它在竖屏模式下有两行,在横屏模式下有三行。可以通过为每个 GridTile
设置 footer
属性来创建标题。
Uses GridView.count
to create a grid that’s 2 tiles
wide in portrait mode, and 3 tiles wide in landscape mode.
The titles are created by setting the footer
property for
each GridTile
.
Dart 代码: Flutter Gallery 中的 grid_list_demo.dart
Dart code: grid_list_demo.dart from the Flutter Gallery。
Widget _buildGrid() => GridView.extent(
maxCrossAxisExtent: 150,
padding: const EdgeInsets.all(4),
mainAxisSpacing: 4,
crossAxisSpacing: 4,
children: _buildGridTileList(30));
// The images are saved with names pic0.jpg, pic1.jpg...pic29.jpg.
// The List.generate() constructor allows an easy way to create
// a list when objects have a predictable naming pattern.
List<Container> _buildGridTileList(int count) => List.generate(
count, (i) => Container(child: Image.asset('images/pic$i.jpg')));
ListView
ListView
,一个和列很相似的 widget,当内容长于自己的渲染盒时,就会自动支持滚动。
ListView
, a column-like widget, automatically
provides scrolling when its content is too long for
its render box.
摘要 (ListView)
Summary (ListView)
-
一个用来组织盒子中列表的专用
Column
A specialized
Column
for organizing a list of boxes -
可以水平或者垂直布局
Can be laid out horizontally or vertically
-
当监测到空间不足时,会提供滚动
Detects when its content won’t fit and provides scrolling
-
比
Column
的配置少,使用更容易,并且支持滚动Less configurable than
Column
, but easier to use and supports scrolling
示例 (ListView)
Examples (ListView)
使用 ListView
的业务列表,它使用了多个 ListTile
。Divider
将餐厅从剧院中分隔开。
Uses ListView
to display a list of businesses using
ListTile
s. A Divider
separates the theaters from
the restaurants.
App 源码: grid_and_list
App source: grid_and_list
使用 ListView
展示特定颜色系列
Material Design 调色板 中的 Colors
。
Uses ListView
to display the Colors
from
the Material Design palette
for a particular color family.
Dart 代码: Flutter Gallery 中的 colors_demo.dart。
Dart code: colors_demo.dart from the Flutter Gallery
Widget _buildList() {
return ListView(
children: [
_tile('CineArts at the Empire', '85 W Portal Ave', Icons.theaters),
_tile('The Castro Theater', '429 Castro St', Icons.theaters),
_tile('Alamo Drafthouse Cinema', '2550 Mission St', Icons.theaters),
_tile('Roxie Theater', '3117 16th St', Icons.theaters),
_tile('United Artists Stonestown Twin', '501 Buckingham Way',
Icons.theaters),
_tile('AMC Metreon 16', '135 4th St #3000', Icons.theaters),
const Divider(),
_tile('K\'s Kitchen', '757 Monterey Blvd', Icons.restaurant),
_tile('Emmy\'s Restaurant', '1923 Ocean Ave', Icons.restaurant),
_tile(
'Chaiya Thai Restaurant', '272 Claremont Blvd', Icons.restaurant),
_tile('La Ciccia', '291 30th St', Icons.restaurant),
],
);
}
ListTile _tile(String title, String subtitle, IconData icon) {
return ListTile(
title: Text(title,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
)),
subtitle: Text(subtitle),
leading: Icon(
icon,
color: Colors.blue[500],
),
);
}
Stack
可以使用 Stack
在基础 widget(通常是图片)上排列 widget,
widget 可以完全或者部分覆盖基础 widget。
Use Stack
to arrange widgets on top of a base
widget—often an image. The widgets can completely
or partially overlap the base widget.
摘要 (Stack)
Summary (Stack)
-
用于覆盖另一个 widget
Use for widgets that overlap another widget
-
子列表中的第一个 widget 是基础 widget;后面的子项覆盖在基础 widget 的顶部
The first widget in the list of children is the base widget; subsequent children are overlaid on top of that base widget
-
Stack
的内容是无法滚动的A
Stack
’s content can’t scroll -
你可以剪切掉超出渲染框的子项
You can choose to clip children that exceed the render box
示例 (Stack)
Examples (Stack)
在 CircleAvatar
的上面使用 Stack
覆盖 Container
(在透明的黑色背景上展示它的 Text
)。
Stack
使用 alignment
属性和 Alignment
让文本偏移。
Uses Stack
to overlay a Container
(that displays its Text
on a translucent
black background) on top of a CircleAvatar
.
The Stack
offsets the text using the alignment
property and
Alignment
s.
App 源码: card_and_stack
App source: card_and_stack
使用 Stack
将渐变叠加到图片的顶部,渐变可以将工具栏的图标和图片区分开来。
Uses Stack
to overlay an icon on top of an image.
Dart 代码: Flutter Gallery 中的 bottom_navigation_demo.dart。
Dart code: bottom_navigation_demo.dart from the Flutter Gallery
Widget _buildStack() {
return Stack(
alignment: const Alignment(0.6, 0.6),
children: [
const CircleAvatar(
backgroundImage: AssetImage('images/pic.jpg'),
radius: 100,
),
Container(
decoration: const BoxDecoration(
color: Colors.black45,
),
child: const Text(
'Mia B',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
);
}
Card
Material 库 中的 Card
包含相关有价值的信息,几乎可以由任何 widget 组成,但是通常和 ListTile
一起使用。
Card
只有一个子项,这个子项可以是列、行、列表、网格或者其他支持多个子项的 widget。默认情况下,Card
的大小是 0x0 像素。你可以使用 SizedBox
控制 card 的大小。
A Card
, from the Material library,
contains related nuggets of information and can
be composed from almost any widget, but is often used with
ListTile
. Card
has a single child,
but its child can be a column, row, list, grid,
or other widget that supports multiple children.
By default, a Card
shrinks its size to 0 by 0 pixels.
You can use SizedBox
to constrain the size of a card.
在 Flutter 中,Card
有轻微的圆角和阴影来使它具有 3D 效果。改变 Card
的 elevation
属性可以控制阴影效果。例如,把 elevation 设置为 24,可以从视觉上更多的把 Card
抬离表面,使阴影变得更加分散。关于支持的 elevation 的值的列表,可以查看 Material guidelines 中的 Elevation。使用不支持的值则会使阴影无效。
In Flutter, a Card
features slightly rounded corners
and a drop shadow, giving it a 3D effect.
Changing a Card
’s elevation
property allows you to control
the drop shadow effect. Setting the elevation to 24,
for example, visually lifts the Card
further from the
surface and causes the shadow to become more dispersed.
For a list of supported elevation values, see Elevation in the
Material guidelines.
Specifying an unsupported value disables the drop shadow entirely.
摘要 (Card)
Summary (Card)
-
实现一个 Material card
Implements a Material card
-
用于呈现相关有价值的信息
Used for presenting related nuggets of information
-
接收单个子项,但是子项可以是
Row
、Column
或者其他可以包含列表子项的 widgetAccepts a single child, but that child can be a
Row
,Column
, or other widget that holds a list of children -
显示圆角和阴影
Displayed with rounded corners and a drop shadow
-
Card
的内容无法滚动A
Card
’s content can’t scroll -
来自 Material 库
From the Material library
示例 (Card)
Examples (Card)
包含 3 个 ListTile 的 Card
,并且通过被 SizedBox
包住来调整大小。
Divider
分隔了第一个和第二个 ListTiles
。
A Card
containing 3 ListTiles and sized by wrapping
it with a SizedBox
. A Divider
separates the first
and second ListTiles
.
App 源码: card_and_stack
App source: card_and_stack
包含图片和文本的 Card
。
A Card
containing an image and text.
Dart 代码: Flutter Gallery 中的 cards_demo.dart
Dart code: cards_demo.dart from the Flutter Gallery
Widget _buildCard() {
return SizedBox(
height: 210,
child: Card(
child: Column(
children: [
ListTile(
title: const Text(
'1625 Main Street',
style: TextStyle(fontWeight: FontWeight.w500),
),
subtitle: const Text('My City, CA 99984'),
leading: Icon(
Icons.restaurant_menu,
color: Colors.blue[500],
),
),
const Divider(),
ListTile(
title: const Text(
'(408) 555-1212',
style: TextStyle(fontWeight: FontWeight.w500),
),
leading: Icon(
Icons.contact_phone,
color: Colors.blue[500],
),
),
ListTile(
title: const Text('costa@example.com'),
leading: Icon(
Icons.contact_mail,
color: Colors.blue[500],
),
),
],
),
),
);
}
ListTile
ListTile
是 Material 库 中专用的行 widget,它可以很轻松的创建一个包含三行文本以及可选的行前和行尾图标的行。
ListTile
在 Card
或者 ListView
中最常用,但是也可以在别处使用。
Use ListTile
, a specialized row widget from the
Material library, for an easy way to create a row
containing up to 3 lines of text and optional leading
and trailing icons. ListTile
is most commonly used in
Card
or ListView
, but can be used elsewhere.
摘要 (ListTile)
Summary (ListTile)
-
一个可以包含最多 3 行文本和可选的图标的专用的行
A specialized row that contains up to 3 lines of text and optional icons
-
比
Row
更少的配置,更容易使用Less configurable than
Row
, but easier to use -
来自 Material 库
From the Material library
示例 (ListTile)
Examples (ListTile)
包含 3 个 ListTiles
的 Card
。
A Card
containing 3 ListTile
s.
App 源码: card_and_stack
App source: card_and_stack
leading wiget 使用 ListTile
。
Uses ListTile
with leading widgets.
Dart 代码: Flutter Gallery 中的 list_demo.dart。
Dart code: list_demo.dart from the Flutter Gallery
Constraints
To fully understand Flutter’s layout system, you need to learn how Flutter positions and sizes the components in a layout. For more information, see Understanding constraints.
视频
Videos
下面的视频是 Flutter in Focus 系列的一部分,解释了 Stateless 和 Stateful 的 widget。
The following videos, part of the
Flutter in Focus series,
explain Stateless
and Stateful
widgets.
每周 Widget 系列 的每一集都会介绍一个 widget。其中也包括一些布局的 widget。
Each episode of the Widget of the Week series focuses on a widget. Several of them includes layout widgets.
Flutter Widget of the Week playlist
其他资源
Other resources
当写布局代码时,下面的资源可能会帮助到你。
The following resources might help when writing layout code.
-
Layout 教程)
学习如何构建布局。Layout tutorial
Learn how to build a layout. -
核心 Widget 目录
描述了 Flutter 中很多可用的 widget。Widget catalog
Describes many of the widgets available in Flutter. -
给 Web 开发者的 Flutter 指南
对那些熟悉 web 开发的人来说,这页将 HTML/CSS 的功能映射到 Flutter 特性上。HTML/CSS Analogs in Flutter
For those familiar with web programming, this page maps HTML/CSS functionality to Flutter features. -
Flutter Gallery 应用和 代码仓库
Demo app 展示了很多 Material Design widget 和其他的 Flutter 特性。Flutter Gallery running app, repo
Demo app showcasing many Material Design widgets and other Flutter features. -
Flutter API 文档
所有 Flutter 库的参考文档。API reference docs
Reference documentation for all of the Flutter libraries. -
处理边界约束 (Box constraints) 的问题
讨论 widget 是如何受渲染框限制的。Dealing with Box Constraints in Flutter
Discusses how widgets are constrained by their render boxes. -
在 Flutter 中添加资源和图片
解释在你的 app 中如何添加图片和其他资源。Adding assets and images
Explains how to add images and other assets to your app’s package. -
Flutter 从 0 到 1
一位开发者第一次写 Flutter app 的经验分享文章。Zero to One with Flutter
One person’s experience writing his first Flutter app.