Flutter 中文文档:Flutter 中的布局
要点
widgets 是用于构建 UI 的类。
widgets 可以用于布局和展示 UI 元素。
通过组合简单的 widgets 来构建复杂的 widgets。
Flutter 布局的核心机制是 widgets。在 Flutter 中,几乎所有东西都是 widget —— 甚至布局模型都是 widgets。你在 Flutter 应用程序中看到的图像,图标和文本都是 widgets。此外不能直接看到的也是 widgets,例如用来排列、限制和对齐可见 widgets 的行、列和网格。
你可以通过组合 widgets 来构建更复杂的 widgets 来创建布局。比如,下面第一个截图上有 3 个图标,每个图标下面都有一个标签:
第二个截图显示了可视布局,可以看到有一排三列,其中每列包含一个图标和一个标签。
备忘
本教程中的大多数截图都是将 debugPaintSizeEnabled
设置为 true 以后的效果,因此你可以看到可视布局。更多信息可以查看文档中的 可视化调试,它是 调试 Flutter 应用 中的一节。
以下是这个 UI 的 widget 树形图:
图上大部分应该和你预想的一样,但你可能会疑惑 containers(图上粉色显示的)是什么。Container 是一个 widget,允许你自定义其子 widget。举几个例子,如果要添加 padding、margin、边框或背景颜色,你就可以用上 Container
了。
在这个例子中,每个 Text widget 都被放在一个 Container
以添加 padding。整个 Row 也被放在一个 Container
中,以便添加 padding。
这个例子其余部分的 UI 由属性控制。通过 Icon 的 color
属性来设置它的颜色,通过 Text.style
属性来设置文字的字体、颜色、字重等等。列和行有一些属性可以让你指定子项垂直或水平的对齐方式以及子项应占用的空间大小。
1. 布局 widget
如何在 Flutter 中布局单个 widget?本节将介绍如何创建和显示单个 widget。本节还包括一个简单的 Hello World app 的完整代码。
在 Flutter 中,只需几步就可以在屏幕上显示文本、图标或图像。
1.1 选择一个布局 widget
根据你想要对齐或限制可见 widget 的方式从各种 layout widgets 中进行选择,因为这些特性通常会传递它所给包含的 widget。
本例使用将其内容水平和垂直居中的 Center。
1.2 创建一个可见 widget
举个例子,创建一个 Text widget:
Text('Hello World'),
创建一个 Image widget:
Image.asset('images/lake.jpg',fit: BoxFit.cover,
),
创建一个 Icon widget:
Icon(Icons.star,color: Colors.red[500],
),
所有布局 widgets 都具有以下任一项:
一个
child
属性,如果它们只包含一个子项 —— 例如Center
和Container
一个
children
属性,如果它们包含多个子项 —— 例如Row
、Column
、ListView
和Stack
将 Text
widget 添加进 Center
widget:
Center(child: Text('Hello World'),
),
1.4 将布局 widget 添加到页面
一个 Flutter app 本身就是一个 widget,大多数 widgets 都有一个 build() 方法,在 app 的 build()
方法中实例化和返回一个 widget 会让它显示出来。
对于 Material
app,你可以使用 Scaffold widget,它提供默认的 banner、背景颜色,还有用于添加抽屉、提示条和底部列表弹窗的 API。你可以将 Center
widget 直接添加到主页 body
的属性中。
lib/main.dart (MyApp)
class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter layout demo',home: Scaffold(appBar: AppBar(title: Text('Flutter layout demo'),),body: Center(child: Text('Hello World'),),),);}
}
备忘
Material 库 实现了一些遵循 Material Design 原则的 widgets。在设计 UI 时,你可以只使用标准 widgets 库 中的 widgets,也可以使用 Material library 中的 widgets。你可以混合来自两个库的 widgets,可以自定义现有 widgets,也可以构建自己的一组自定义 widgets。
1.5 非 Material apps
对于非 Material app,你可以将 Center
widget 添加到 app 的 build()
方法里:
lib/main.dart (MyApp)
class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(decoration: BoxDecoration(color: Colors.white),child: Center(child: Text('Hello World',textDirection: TextDirection.ltr,style: TextStyle(fontSize: 32,color: Colors.black87,),),),);}
}
默认情况下,非 Material app 不包含 AppBar
、标题和背景颜色。如果你希望在非 Material app 中使用这些功能,则必须自己构建它们。以上 app 将背景颜色更改为白色,将文本更改为深灰色来模拟一个 Material app。
完成! 启动这个 app,你应该能看到 Hello World。
App 源码:
Material app:https://github.com/cfug/flutter.cn/tree/master/examples/layout/base
非 Material app:https://github.com/cfug/flutter.cn/tree/master/examples/layout/non_material
2. 横向或纵向布局多个 widgets
要点
- Row 和 Column 是两种最常用的布局模式。
- Row 和 Column 每个都有一个子 widgets 列表。
- 一个子 widget 本身可以是 Row、Column 或其他复杂 widget。
- 可以指定 Row 或 Column 如何在垂直和水平方向上对齐其子项。
- 可以拉伸或限制特定的子 widgets。
- 可以指定子 widgets 如何占用 Row 或 Column 的可用空间。
2.1 对齐 widgets
mainAxisAlignment
和 crossAxisAlignment
属性控制行或列如何对齐其子项。对于一行来说,主轴水平延伸,交叉轴垂直延伸。对于一列来说,主轴垂直延伸,交叉轴水平延伸。
Image.asset
来显示图像。更多信息可以查看本例的 pubspec.yaml 文件,或文档:添加资源和图片。如果你正在使用 Image.network
引用在线图像,则不需要这些操作。
spaceEvenly
会将空余空间在每个图像之间、之前和之后均匀地划分。
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,children: [Image.asset('images/pic1.jpg'),Image.asset('images/pic2.jpg'),Image.asset('images/pic3.jpg'),],
);
spaceEvenly
会将空余空间在每个图像之间、之上和之下均匀地划分。
Column(mainAxisAlignment: MainAxisAlignment.spaceEvenly,children: [Image.asset('images/pic1.jpg'),Image.asset('images/pic2.jpg'),Image.asset('images/pic3.jpg'),],
);
App 源码:
https://github.com/cfug/flutter.cn/tree/master/examples/layout/row_column
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'),),],
);
Expanded
widget 的 flex
属性,这是一个用来确定 widget 的弹性系数的整数。默认的弹性系数为 1。以下代码将中间图像的弹性系数设置为 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'),),],
);
2.3 组合 widgets
mainAxisSize
设置为 MainAxisSize.min
。以下示例使用此属性将星形图标组合在一起。
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]),Icon(Icons.star, color: Colors.black),Icon(Icons.star, color: Colors.black),],
)
2.4 嵌套行和列
ratings
变量创建了一个行,其中包含较小的由 5 个星形图标和文本组成的一行:
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]),Icon(Icons.star, color: Colors.black),Icon(Icons.star, color: Colors.black),],
);final ratings = Container(padding: EdgeInsets.all(20),child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,children: [stars,Text('170 Reviews',style: TextStyle(color: Colors.black,fontWeight: FontWeight.w800,fontFamily: 'Roboto',letterSpacing: 0.5,fontSize: 20,),),],),
);
iconList
变量定义了图标行:
final 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: EdgeInsets.all(20),child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,children: [Column(children: [Icon(Icons.kitchen, color: Colors.green[500]),Text('PREP:'),Text('25 min'),],),Column(children: [Icon(Icons.timer, color: Colors.green[500]),Text('COOK:'),Text('1 hr'),],),Column(children: [Icon(Icons.restaurant, color: Colors.green[500]),Text('FEEDS:'),Text('4-6'),],),],),),
);
leftColumn
变量包含评级和图标行,以及蛋糕介绍的标题和文本:
final leftColumn = Container(padding: EdgeInsets.fromLTRB(20, 30, 20, 20),child: Column(children: [titleText,subTitle,ratings,iconList,],),
);
Container
中以限制其宽度。最后,UI 由 Card
内的整行(包含左列和图像)构成。
Image.network()
从网络上引用图像,但是在本例图像将保存到项目中的一个图像目录中,添加到 pubspec 文件,并使用 Images.asset()
访问。
body: Center(child: Container(margin: EdgeInsets.fromLTRB(0, 40, 0, 30),height: 600,child: Card(child: Row(crossAxisAlignment: CrossAxisAlignment.start,children: [Container(width: 440,child: leftColumn,),mainImage,],),),),
),
App 源码: https://github.com/cfug/flutter.cn/tree/master/examples/layout/pavlova
3. 通用布局 widgets
3.1 标准 widgets
- Container:向 widget 增加 padding、margins、borders、background color 或者其他的装饰。
- GridView:将 widget 展示为一个可滚动的网格。
- ListView:将 widget 展示为一个可滚动的列表。
- Stack:将 widget 覆盖在另一个的上面。
- Card:将相关信息整理到一个有圆角和阴影的盒子中。
- ListTile:将最多三行的文本、可选的导语以及后面的图标组织在一行中。
Container
中,并且改变它的背景色或者图片,来改变设备的背景。
- 增加 padding、margins、borders
- 改变背景色或者图片
- 只包含一个子 widget,但是这个子 widget 可以是行、列或者是 widget 树的根 widget
Widget _buildImageColumn() => Container(decoration: BoxDecoration(color: Colors.black26,),child: Column(children: [_buildImageRow(1),_buildImageRow(3),],),);
Container
还用来为每个图片添加圆角和外边距:
Widget _buildDecoratedImage(int imageIndex) => Expanded(child: Container(decoration: BoxDecoration(border: Border.all(width: 10, color: Colors.black38),borderRadius: const BorderRadius.all(const 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),],);
3.4 GridView
使用 GridView 将 widget 作为二维列表展示。GridView
提供两个预制的列表,或者你可以自定义网格。当 GridView
检测到内容太长而无法适应渲染盒时,它就会自动支持滚动。
摘要 (GridView)
- 在网格中使用 widget
- 当列的内容超出渲染容器的时候,它会自动支持滚动。
- 创建自定义的网格,或者使用下面提供的网格的其中一个:
GridView.count
允许你制定列的数量GridView.extent
允许你制定单元格的最大宽度
示例 (GridView)
使用
GridView.extent
创建一个最大宽度为 150 像素的网格。App 源码:
https://github.com/cfug/flutter.cn/tree/master/examples/layout/grid_and_list
使用
GridView.count
创建一个网格,它在竖屏模式下有两行,在横屏模式下有三行。可以通过为每个 GridTile 设置footer
属性来创建标题。Dart 代码:https://github.com/flutter/flutter/blob/master/examples/flutter_gallery/lib/demo/material/grid_list_demo.dart
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')));
3.5 ListView
- 一个用来组织盒子中列表的专用 Column
- 可以水平或者垂直布局
- 当监测到空间不足时,会提供滚动
比
Column
的配置少,使用更容易,并且支持滚动
ListView
的业务列表,它使用了多个 ListTile
。Divider
将餐厅从剧院中分隔开。
ListView
展示特定颜色系列 Material Design 调色板 中的 颜色
Widget _buildList() => 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),Divider(),_tile('Kescaped_code#39;s Kitchen', '757 Monterey Blvd', Icons.restaurant),_tile('Emmyescaped_code#39;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) => ListTile(title: Text(title,style: TextStyle(fontWeight: FontWeight.w500,fontSize: 20,)),subtitle: Text(subtitle),leading: Icon(icon,color: Colors.blue[500],),);
- 用于覆盖另一个 widget
- 子列表中的第一个 widget 是基础 widget;后面的子项覆盖在基础 widget 的顶部
Stack
的内容是无法滚动的- 你可以编辑超出渲染框的子项
CircleAvatar
的上面使用 Stack
覆盖 Container
(在透明的黑色背景上展示它的 Text
)。Stack
使用 alignment
属性和 Alignment
让文本偏移。
Stack
将渐变叠加到图片的顶部。渐变可以将工具栏的图标和图片区分开来。
Widget _buildStack() => Stack(alignment: const Alignment(0.6, 0.6),children: [CircleAvatar(backgroundImage: AssetImage('images/pic.jpg'),radius: 100,),Container(decoration: BoxDecoration(color: Colors.black45,),child: Text('Mia B',style: TextStyle(fontSize: 20,fontWeight: FontWeight.bold,color: Colors.white,),),),],);
Card
只有一个子项,这个子项可以是列、行、列表、网格或者其他支持多个子项的 widget。默认情况下,Card
的大小是 0x0 像素。你可以使用 SizedBox 控制 card 的大小。
Card
有轻微的圆角和阴影来使它具有 3D 效果。改变 Card
的 elevation
属性可以控制阴影效果。例如,把 elevation 设置为 24,可以从视觉上更多的把 Card
抬离表面,使阴影变得更加分散。关于支持的 elevation 的值的列表,可以查看 Material guidelines 中的 Elevation。使用不支持的值则会使阴影无效。
- 实现一个 Material card
- 用于呈现相关有价值的信息
- 接收单个子项,但是子项可以是
Row
、Column
或者其他可以包含列表子项的 widget - 显示圆角和阴影
Card
的内容无法滚动- 来自 Material 库
Card
,并且通过被 SizedBox
包住来调整大小。Divider
分隔了第一个和第二个 ListTiles
。
Card
。
Widget _buildCard() => SizedBox(height: 210,child: Card(child: Column(children: [ListTile(title: Text('1625 Main Street',style: TextStyle(fontWeight: FontWeight.w500)),subtitle: Text('My City, CA 99984'),leading: Icon(Icons.restaurant_menu,color: Colors.blue[500],),),Divider(),ListTile(title: Text('(408) 555-1212',style: TextStyle(fontWeight: FontWeight.w500)),leading: Icon(Icons.contact_phone,color: Colors.blue[500],),),ListTile(title: Text('costa@example.com'),leading: Icon(Icons.contact_mail,color: Colors.blue[500],),),],),),);
ListTile
在 Card 或者 ListView 中最常用,但是也可以在别处使用。
- 一个可以包含最多 3 行文本和可选的图标的专用的行
- 比
Row
更少的配置,更容易使用 - 来自 Material 库
ListTiles
的 Card
。
ListTile
列出 3 个下拉按钮类型。
- Layout 教程
学习如何构建布局。链接:https://flutter.cn/docs/development/ui/layout/tutorial
- 核心 Widget 目录
描述了 Flutter 中很多可用的 widget。链接:https://flutter.cn/docs/development/ui/widgets
对那些熟悉 web 开发的人来说,这页将 HTML/CSS 的功能映射到 Flutter 特性上。- Flutter Gallery
Demo app 展示了很多 Material Design widget 和其他的 Flutter 特性。链接:https://github.com/flutter/flutter/tree/master/examples/flutter_gallery - Flutter API 文档
所有 Flutter 库的参考文档。链接:https://api.flutter-io.cn/index.html - 处理边界约束 (Box constraints) 的问题
讨论 widget 是如何受渲染框限制的。链接:https://flutter.cn/docs/development/ui/layout/box-constraints - 在 Flutter 中添加资源和图片
解释在你的 app 中如何添加图片和其他资源。链接:https://flutter.cn/docs/development/ui/assets-and-images - Flutter 从 0 到 1
一位开发者第一次写 Flutter app 的经验分享文章。链接:https://medium.com/@mravn/zero-to-one-with-flutter-43b13fd7b354
Flutter 中文文档:Flutter 中的布局相关推荐
- javax.servlet-api 简介、中文文档、中英对照文档 下载
javax.servlet-api 文档 下载链接(含jar包.源码.pom) 组件名称 中文-文档-下载链接 中英对照-文档-下载链接 javax.servlet-api-3.1.0.jar 暂无 ...
- easyexcel 简介、中文文档、中英对照文档 下载
easyexcel 文档 下载链接(含jar包.源码.pom) 组件名称 中文-文档-下载链接 中英对照-文档-下载链接 easyexcel-3.0.5.jar easyexcel-3.0.5-API ...
- commons-lang3 简介、中文文档、中英对照文档 下载
commons-lang3 文档 下载链接(含jar包.源码.pom) 组件名称 中文-文档-下载链接 中英对照-文档-下载链接 commons-lang3-3.10.jar commons-lang ...
- itext 简介、中文文档、中英对照文档 下载
itext 文档 下载链接(含jar包.源码.pom) 组件名称 中文-文档-下载链接 中英对照-文档-下载链接 itext-2.1.7.jar itext-2.1.7-API文档-中文版.zip i ...
- docx4j 简介、中文文档、中英对照文档 下载
docx4j 文档 下载链接(含jar包.源码.pom) 组件名称 中文-文档-下载链接 中英对照-文档-下载链接 docx4j-3.3.5.jar docx4j-3.3.5-API文档-中文版.zi ...
- mybatis 简介、中文文档、中英对照文档 下载
mybatis 文档 下载链接(含jar包.源码.pom) 组件名称 中文-文档-下载链接 中英对照-文档-下载链接 mybatis-3.2.8.jar mybatis-3.2.8-API文档-中文版 ...
- snakeyaml 简介、中文文档、中英对照文档 下载
snakeyaml 文档 下载链接(含jar包.源码.pom) 组件名称 中文-文档-下载链接 中英对照-文档-下载链接 snakeyaml-1.12.jar snakeyaml-1.12-API文档 ...
- jsqlparser 简介、中文文档、中英对照文档 下载
jsqlparser 文档 下载链接(含jar包.源码.pom) 组件名称 中文-文档-下载链接 中英对照-文档-下载链接 jsqlparser-0.9.5.jar jsqlparser-0.9.5- ...
- aws-java-sdk-s3 简介、中文文档、中英对照文档 下载
aws-java-sdk-s3 文档 下载链接(含jar包.源码.pom) 组件名称 中文-文档-下载链接 中英对照-文档-下载链接 aws-java-sdk-s3-1.11.939.jar aws- ...
- spring-data-redis 简介、中文文档、中英对照文档 下载
spring-data-redis 文档 下载链接(含jar包.源码.pom) 组件名称 中文-文档-下载链接 中英对照-文档-下载链接 spring-data-redis-1.7.5.RELEASE ...
最新文章
- UOJ.311.[UNR#2]积劳成疾(DP)
- Android-6步教你自定义View
- C++ Primer 5th笔记(chap 18 大型程序工具)类型转换与多个基类
- Spring面试问题
- teamviewer设备数量上限怎么解决_支小蜜刷脸支付设备解决方案,支小蜜刷脸支付设备怎么使用...
- python threading.Timer
- linux 的一些实用工具,linux 命令行下的一些实用工具
- Java中split函数的用法及使用示例
- 在本地搭建hyperledger fabric 网络
- ConceptDraw Office for mac(跨平台图表办公程序)
- Photoshop/PS中如何写维吾尔语等语言 乱码
- redis 默认过期策略_redis 过期策略
- 程序员坐牢了,会被安排去写代码吗?
- 用JSDoc生成js文档
- 计算机系统文件命名规则,Windows10系统怎样自定义副本文件默认命名规则
- python开发抢票软件_python自动抢票神器
- 如何建立微信微社区?
- 查找整数c语言程序,查找整数(示例代码)
- 推荐一个自动破解替换密码的工具
- 浙江独立学院计算机专业排名2015,2018中国独立学院排行榜发布,浙江这所独立学院独占鳌头!...
热门文章
- 你的能力是更适合做微商还是淘宝
- librosa 语音库(三) librosa.feature. 中的 spectrogram 与 melspectrogram
- Truffle - 2 利用Truffle编写、测试智能合约并将其部署到不同的测试网络
- PS画等分圆环的技巧
- c3po数据库连接池简单配置
- Domain Adaptation for Object Detection using SE Adaptors and Center Loss 论文翻译
- Linux系统安装make命令(错误提醒:Failed to search for file: Cannot update read-only repo)
- cubemx 配置多通道ADC进行ADC采样
- 最短路计数(dp+最短路)
- 重启tomcat命令