你将学到什么?html
- Flutter的布局机制如何工做。
- 如何垂直和水平布局小部件。
- 如何构建一个Flutter布局。
这是在Flutter中构建布局的指南。 您将构建如下屏幕截图的布局:java
而后本指南回过头来解释Flutter的布局方法,并说明如何在屏幕上放置一个小部件。 在讨论如何水平和垂直放置小部件以后,会介绍一些最多见的布局小部件。git
创建布局github
Flutter的布局方法
布置一个小部件
垂直和水平放置多个小部件web
常见的布局小部件编程
资源浏览器
若是您想要了解布局机制的“全貌”,请从Flutter的布局方法开始。网络
首先,获取代码:app
接下来,将图像添加到示例中:框架
第一步是将布局打破成其基本要素:
首先,肯定更大的元素。 在这个例子中,四个元素排列成一列:一个图像,两行和一个文本块。
接下来,绘制每一行。 第一行称为标题部分,有三个孩子:一列文字,一个星形图标和一个数字。 它的第一个孩子,列,包含2行文字。 第一列占用大量空间,因此它必须包装在扩展小部件中。
第二行称为按钮部分,也有3个子项:每一个子项都是一个包含图标和文本的列。
一旦布局结束,最简单的就是采起自下而上的方法来实现它。 为了最大限度地减小深度嵌套布局代码的视觉混淆,将一些实现放置在变量和函数中。
首先,您将在标题部分构建左栏。 将列放入扩展窗口小部件中会拉伸该列以使用该行中的全部剩余空闲空间。 将crossAxisAlignment属性设置为CrossAxisAlignment.start可将列置于行的开始位置。
将第一行文本放入Container中能够添加填充。 列中的第二个子项(也是文本)显示为灰色。
标题行中的最后两项是一个红色的星形图标和文字“41”。 将整行放在容器中,并沿着每一个边缘填充32像素。
这是实现标题行的代码。
注意:若是有什么问题,对照GitHub上的lib/main.dart检查代码
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { Widget titleSection = new Container( padding: const EdgeInsets.all(32.0), child: new Row( children: [ new Expanded( child: new Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ new Container( padding: const EdgeInsets.only(bottom: 8.0), child: new Text( 'Oeschinen Lake Campground', style: new TextStyle( fontWeight: FontWeight.bold, ), ), ), new Text( 'Kandersteg, Switzerland', style: new TextStyle( color: Colors.grey[500], ), ), ], ), ), new Icon( Icons.star, color: Colors.red[500], ), new Text('41'), ], ), ); //... }
提示:将代码粘贴到应用程序中时,缩进可能会变形。 您能够经过右键单击Dart代码并选择使用Reformat with Dart Style来在IntelliJ中修复此问题。 或者,在命令行中,您可使用dartfmt。
提示:为了得到更快的开发体验,请尝试使用Flutter的热从新加载功能。 热从新加载容许您修改代码并查看更改,而无需彻底从新启动应用程序。 IntelliJ的Flutter插件支持热重载,或者您能够从命令行触发。 有关更多信息,请参阅Hot Reloads与完整应用程序从新启动。
按钮部分包含3列,它们使用相同的布局 - 一行文本上的图标。 此行中的列均匀分布,文本和图标用主颜色绘制,在应用程序的build()方法中将其设置为蓝色:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { //... return new MaterialApp( title: 'Flutter Demo', theme: new ThemeData( primarySwatch: Colors.blue, ), //... }
因为构建每一行的代码几乎是相同的,所以建立一个嵌套函数(如buildButtonColumn()(它接受一个Icon和Text)并返回一个列以其主要颜色绘制的小部件的效率最高。
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { //... Column buildButtonColumn(IconData icon, String label) { Color color = Theme.of(context).primaryColor; return new Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ new Icon(icon, color: color), new Container( margin: const EdgeInsets.only(top: 8.0), child: new Text( label, style: new TextStyle( fontSize: 12.0, fontWeight: FontWeight.w400, color: color, ), ), ), ], ); } //... }
构建函数将图标直接添加到列中。 将文本放入容器以在文本上方添加填充,将其与图标分开。
经过调用函数并传递特定于该列的图标和文原本构建包含这些列的行。 使用MainAxisAlignment.spaceEvenly沿着主轴对齐列,以在每列以前,之间和以后均匀排列空闲空间。
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { //... Widget buttonSection = new Container( child: new Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ buildButtonColumn(Icons.call, 'CALL'), buildButtonColumn(Icons.near_me, 'ROUTE'), buildButtonColumn(Icons.share, 'SHARE'), ], ), ); //... }
将至关长的文本部分定义为变量。 将文本放入容器中,以便沿每条边添加32像素的填充。 softwrap属性指示文本是否应在软换行符(如句点或逗号)上断开。
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { //... Widget textSection = new Container( padding: const EdgeInsets.all(32.0), child: new Text( ''' Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese Alps. Situated 1,578 meters above sea level, it is one of the larger Alpine Lakes. A gondola ride from Kandersteg, followed by a half-hour walk through pastures and pine forest, leads you to the lake, which warms to 20 degrees Celsius in the summer. Activities enjoyed here include rowing, and riding the summer toboggan run. ''', softWrap: true, ), ); //... }
四列元素中的三个如今完成,只留下图像。 该图片能够在Creative Commons许可下在线得到,可是它大并且缓慢。 在步骤0中,您将该图像包含在项目中并更新了pubspec文件,以便如今能够从代码中引用它:
body: new ListView( children: [ new Image.asset( 'images/lake.jpg', height: 240.0, fit: BoxFit.cover, ), // ... ], )
BoxFit.cover告诉框架,图像应尽量小,但覆盖整个渲染框。
在最后一步,你将这些碎片组装在一块儿。 这些小部件安排在ListView中,而不是列中,由于在小设备上运行应用程序时,ListView会自动滚动。
//... body: new ListView( children: [ new Image.asset( 'images/lake.jpg', width: 600.0, height: 240.0, fit: BoxFit.cover, ), titleSection, buttonSection, textSection, ], ), //...
Dart代码:main.dart
Image:images
Pubspec:pubspec.yaml
而已! 当您从新加载应用程序时,应该会看到截图中显示的相同布局。 您能够经过将交互添加到您的Flutter应用中来为此布局添加交互功能。
Flutter的布局方法
重点是什么?
- 小部件是用于构建UI的类。
- 小部件用于布局和UI元素。
- 撰写简单的小部件来构建复杂的小部件。
Flutter的布局机制的核心是小部件。 在Flutter中,几乎全部东西都是一个小部件 - 甚至布局模型都是小部件。 您在Flutter应用中看到的图像,图标和文本都是小部件。 可是你看不到的东西也是小部件,例如排列,约束和对齐可见小部件的行,列和网格。
您能够经过构建小部件来建立布局来构建更复杂的小部件。 例如,左边的屏幕截图显示了3个图标,每一个图标下有一个标签:
第二个屏幕截图显示可视布局,显示一列3列,其中每列包含一个图标和一个标签。
注意:本教程中的大多数屏幕截图均以debugPaintSizeEnabled设置为true显示,以便您能够看到可视布局。 有关更多信息,请参阅可视化调试,这是调试Flutter应用程序中的一部分
如下是此UI的部件树图:
大部分应该看起来像你所指望的,但你可能想知道容器(以粉红色显示)。 容器是一个小部件,容许您自定义其子部件。 若是要添加填充,边距,边框或背景色,请使用容器来命名其某些功能。
在这个例子中,每一个文本小部件放置在容器中以添加边距。 整个行也被放置在容器中以在行的周围添加填充。
本例中的其他UI由属性控制。 使用其color属性设置图标的颜色。 使用文本的style属性来设置字体,颜色,重量等等。 列和行的属性容许您指定他们的孩子如何垂直或水平对齐,以及儿童应该占据多少空间。
重点是什么?
- 即便应用程序自己也是一个小部件。
- 建立一个小部件并将其添加到布局小部件很容易。
- 要在设备上显示小部件,请将布局小部件添加到应用小部件。
- 使用Scaffold是最容易的,它是Material Components库中的一个小部件,它提供了一个默认横幅,背景颜色,而且具备添加抽屉,小吃店和底部表单的API。
- 若是您愿意,能够构建仅使用小部件库中的标准小部件的应用程序。
如何在Flutter中布置单个小部件? 本节介绍如何建立一个简单的小部件并将其显示在屏幕上。 它还显示了一个简单的Hello World应用程序的完整代码。
在Flutter中,只需几个步骤便可在屏幕上放置文本,图标或图像。
1.选择一个布局小部件来保存该对象。
根据您想要对齐或约束可见窗口小部件的方式,从各类布局窗口小部件中进行选择,由于这些特性一般会传递到包含的窗口小部件。 这个例子使用Center,它将内容水平和垂直居中。
2.建立一个小部件来容纳可见对象。
注意:Flutter应用程序是用Dart语言编写的。 若是您了解Java或相似的面向对象编程语言,Dart会感到很是熟悉。 若是不是的话,你能够试试DartPad,一个能够在任何浏览器上使用的交互式Dart练习。 语言游览提供了Dart语言功能的概述。
例如,建立一个文本小部件:
new Text('Hello World', style: new TextStyle(fontSize: 32.0))
建立一个图像小部件:
new Image.asset('images/myPic.jpg', fit: BoxFit.cover)
建立一个图标小部件:
new Icon(Icons.star, color: Colors.red[500])
3.将可见小部件添加到布局小部件。
若是全部布局小部件带有一个子元素(例如Center或Container),则它们具备一个child属性,若是它们带有小部件列表(例如Row,Column,ListView或Stack),则它们具备children属性。
将文本小部件添加到中心小部件:
new Center( child: new Text('Hello World', style: new TextStyle(fontSize: 32.0))
4.将布局小部件添加到页面。
Flutter应用自己就是一个小部件,大部分小部件都有一个build()方法。 在应用程序的构建方法中声明小部件会在设备上显示小部件。
对于Material应用程序,您能够将Center小部件直接添加到主页的body属性。
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Text('Hello World', style: new TextStyle(fontSize: 32.0)), ), ); } }
注意:Material Components库实现了遵循Material Design原则的小部件。 在设计用户界面时,您能够专门使用标准小部件库中的小部件,也可使用材质部件中的小部件。 您能够混合使用两个库中的小部件,您能够自定义现有的小部件,也能够构建本身的一组定制小部件。
对于非Material应用程序,您能够将Center小部件添加到应用程序的build()方法中:
// This app doesn't use any Material Components, such as Scaffold. // Normally, an app that doesn't use Scaffold has a black background // and the default text color is black. This app changes its background // to white and its text color to dark grey to mimic a Material app. import 'package:flutter/material.dart'; void main() { runApp(new MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new Container( decoration: new BoxDecoration(color: Colors.white), child: new Center( child: new Text('Hello World', style: new TextStyle(fontSize: 40.0, color: Colors.black87)), ), ); } }
请注意,默认状况下,非Material应用程序不包含AppBar,标题或背景颜色。 若是您想在非Material应用程序中使用这些功能,您必须本身构建它们。 此应用程序将背景颜色更改成白色,将文本更改成深灰色以模仿Material应用程序。
而已! 当你运行这个应用时,你应该看到:
Dart code (Material app): main.dart
Dart code (widgets-only app): main.dart
最多见的布局模式之一是垂直或水平排列小部件。 您可使用“行”小部件水平排列小部件,并使用“列”小部件垂直排列小部件。
重点是什么?
- 行和列是两种最经常使用的布局模式。
- 行和列分别获取子窗口小部件的列表。
- 子小部件自己能够是行,列或其余复杂小部件。
- 您能够指定行或列如何在垂直和水平方向上对齐其子项。
- 您能够拉伸或限制特定的子部件。
- 您能够指定子窗口小部件如何使用行或列的可用空间。
内容
要在Flutter中建立行或列,能够将一个子窗口小部件列表添加到Row或Column窗口小部件中。 反过来,每一个孩子自己能够是一排或一列,依此类推。 如下示例显示如何在行或列内嵌套行或列。
此布局按行组织。 该行包含两个孩子:左侧的一列和右侧的图片:
左列的小部件树嵌套行和列。
您将在嵌套行和列中实现一些Pavlova的布局代码。
注意:行和列是水平和垂直布局的基本原始小部件 - 这些低级小部件容许最大化的自定义。 Flutter还提供专门的,更高级别的小部件,可能足以知足您的需求。 例如,您可能更喜欢ListTile,而不是Row,而ListTile是一个易于使用的小部件,具备前导和尾随图标属性以及最多3行文本。 您可能更喜欢ListView,而不是列,您可能更喜欢ListView,这是一种列状布局,若是其内容太长而没法适应可用空间,则会自动滚动。 有关更多信息,请参阅通用布局小部件。
您可使用mainAxisAlignment和crossAxisAlignment属性控制行或列的排列方式。 对于一排,主轴水平延伸,横轴垂直延伸。 对于一列,主轴垂直运行,横轴水平运行。
MainAxisAlignment和CrossAxisAlignment类提供了用于控制对齐的各类常量。
注意:将图像添加到项目中时,须要更新pubspec文件才能访问它们 - 此示例使用Image.asset来显示图像。 有关更多信息,请参阅此示例的pubspec.yaml文件,或在Flutter中添加资源和图像。 若是您使用Image.network来引用联机图像,则不须要执行此操做。
在如下示例中,3个图像中的每个都是100像素宽。 渲染框(在这种状况下,整个屏幕)宽度超过300像素,所以将主轴对齐设置为spaceEvenly在每一个图像之间,以前和以后均匀分配自由水平空间。
appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ new Image.asset('images/pic1.jpg'),
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
列的工做方式与行相同。 如下示例显示了一列3个图像,每一个图像高100个像素。 渲染盒(在这种状况下,整个屏幕)的高度大于300像素,所以将主轴对齐设置为spaceEvenly将自由垂直空间均匀分配在每一个图像之间,之上和之下。
appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ new Image.asset('images/pic1.jpg'),
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
注意:若是布局太大而不适合设备,则会在受影响的边缘出现红色条纹。 例如,如下截图中的行对于设备的屏幕来讲太宽:
经过使用“扩展”窗口小部件,能够将窗口小部件的大小设置为适合行或列,这在下面的“调整窗口小部件”部分进行了描述。
也许你想要一个小部件占据其兄弟姐妹两倍的空间。 您能够将行或列的子项放置在扩展小部件中,以控制沿着主轴的小部件大小。 扩展小部件具备flex属性,它是一个整数,用于肯定小部件的弹性因子。 扩展小部件的默认弹性因子是1。
例如,要建立一个由三个小部件组成的行,其中中间小部件的宽度是其余两个小部件的两倍,请将中间小部件的弹性系数设置为2:
appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ new Expanded( child: new Image.asset('images/pic1.jpg'), ), new Expanded( flex: 2, child: new Image.asset('images/pic2.jpg'), ), new Expanded(
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
要修复上一节中的示例,其中3行图像的行对于其渲染框太宽,而且致使红色条带,请使用扩展小部件包装每一个小部件。 默认状况下,每一个小部件的弹性因子为1,将行的三分之一分配给每一个小部件。
appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ new Expanded( child: new Image.asset('images/pic1.jpg'), ), new Expanded( child: new Image.asset('images/pic2.jpg'), ), new Expanded(
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
默认状况下,行或列沿着其主轴占据尽量多的空间,但若是要将子项紧密包装在一块儿,请将mainAxisSize设置为MainAxisSize.min。 如下示例使用此属性将星形图标打包在一块儿。
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { var packedRow = new Row( mainAxisSize: MainAxisSize.min, children: [ new Icon(Icons.star, color: Colors.green[500]), new Icon(Icons.star, color: Colors.green[500]), new Icon(Icons.star, color: Colors.green[500]), new Icon(Icons.star, color: Colors.black), new Icon(Icons.star, color: Colors.black), ], ); // ... }
Dart code: main.dart
Icons: Icons class
Pubspec: pubspec.yaml
布局框架容许您根据须要在行和列内部嵌套行和列。 让咱们看下面布局的概述部分的代码:
概述部分实现为两行。 评级行包含五颗星和评论数量。 图标行包含三列图标和文本。
评级行的小部件树:
ratings变量建立一行,其中包含一行较小的5星形图标和文本:
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { //... var ratings = new Container( padding: new EdgeInsets.all(20.0), child: new Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ new Row( mainAxisSize: MainAxisSize.min, children: [ new Icon(Icons.star, color: Colors.black), new Icon(Icons.star, color: Colors.black), new Icon(Icons.star, color: Colors.black), new Icon(Icons.star, color: Colors.black), new Icon(Icons.star, color: Colors.black), ], ), new Text( '170 Reviews', style: new TextStyle( color: Colors.black, fontWeight: FontWeight.w800, fontFamily: 'Roboto', letterSpacing: 0.5, fontSize: 20.0, ), ), ], ), ); //... } }
提示:为了最大限度地减小由嵌套严重的布局代码致使的视觉混淆,能够在变量和函数中实现UI的各个部分。
评级行下方的图标行包含3列; 每一个列都包含一个图标和两行文本,您能够在其小部件树中看到:
iconList变量定义图标行:
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { // ... var descTextStyle = new TextStyle( color: Colors.black, fontWeight: FontWeight.w800, fontFamily: 'Roboto', letterSpacing: 0.5, fontSize: 18.0, height: 2.0, ); // DefaultTextStyle.merge allows you to create a default text // style that is inherited by its child and all subsequent children. var iconList = DefaultTextStyle.merge( style: descTextStyle, child: new Container( padding: new EdgeInsets.all(20.0), child: new Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ new Column( children: [ new Icon(Icons.kitchen, color: Colors.green[500]), new Text('PREP:'), new Text('25 min'), ], ), new Column( children: [ new Icon(Icons.timer, color: Colors.green[500]), new Text('COOK:'), new Text('1 hr'), ], ), new Column( children: [ new Icon(Icons.restaurant, color: Colors.green[500]), new Text('FEEDS:'), new Text('4-6'), ], ), ], ), ), ); // ... } }
leftColumn变量包含评分和图标行,以及描述Pavlova的标题和文本:
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { //... var leftColumn = new Container( padding: new EdgeInsets.fromLTRB(20.0, 30.0, 20.0, 20.0), child: new Column( children: [ titleText, subTitle, ratings, iconList, ], ), ); //... } }
左列放置在容器中以约束其宽度。 最后,用Card的整个行(包含左列和图像)构建UI。
Pavlova图片来自Pixabay,能够在Creative Commons许可下使用。 您可使用Image.network从网络中嵌入图像,但对于此示例,图像将保存到项目中的图像目录中,添加到pubspec文件并使用Images.asset访问。 有关更多信息,请参阅在Flutter中添加资产和图像。
body: new Center( child: new Container( margin: new EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0), height: 600.0, child: new Card( child: new Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ new Container( width: 440.0, child: leftColumn, ), mainImage, ], ), ), ), ),
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
提示:Pavlova示例在普遍的设备(如平板电脑)上水平运行效果最佳。 若是您在iOS模拟器中运行此示例,则可使用Hardware > Device菜单选择其余设备。 对于这个例子,咱们推荐iPad Pro。 您可使用Hardware > Rotate将其方向更改成横向模式。 您还可使用Window > Scale更改模拟器窗口的大小(不更改逻辑像素的数量)。
Flutter拥有丰富的布局小部件库,但这里有一些最经常使用的布局部件。 其目的是尽量快地启动并运行,而不是让您完整列出。 有关其余可用小部件的信息,请参阅小部件概述,或使用API参考文档中的搜索框。 此外,API文档中的小部件页面常常会提供有关可能更适合您需求的相似小部件的建议。
如下小部件分为两类:小部件库中的标准小部件和材质组件库中的专用小部件。 任何应用程序均可以使用小部件库,但只有Material应用程序可使用Material Components库。
Material Components
许多布局会自由使用Container来使用填充分隔小部件,或者添加边框或边距。 您能够经过将整个布局放入Container并更改其背景颜色或图像来更改设备的背景。
容器概要:
容器示例:
除了下面的例子以外,本教程中的许多示例都使用Container。 您还能够在Flutter Gallery中找到更多容器示例。
该布局由两列组成,每列包含2个图像。 每一个图像使用一个Container来添加一个圆形的灰色边框和边距。 包含图像行的列使用容器将背景颜色更改成浅灰色。
Dart code: main.dart,下面的代码段
Images: images
Pubspec: pubspec.yaml
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { var container = new Container( decoration: new BoxDecoration( color: Colors.black26, ), child: new Column( children: [ new Row( children: [ new Expanded( child: new Container( decoration: new BoxDecoration( border: new Border.all(width: 10.0, color: Colors.black38), borderRadius: const BorderRadius.all(const Radius.circular(8.0)), ), margin: const EdgeInsets.all(4.0), child: new Image.asset('images/pic1.jpg'), ), ), new Expanded( child: new Container( decoration: new BoxDecoration( border: new Border.all(width: 10.0, color: Colors.black38), borderRadius: const BorderRadius.all(const Radius.circular(8.0)), ), margin: const EdgeInsets.all(4.0), child: new Image.asset('images/pic2.jpg'), ), ), ], ), // ... // See the definition for the second row on GitHub: // https://raw.githubusercontent.com/flutter/website/master/_includes/code/layout/container/main.dart ], ), ); //... } }
使用GridView将小部件放置为二维列表。 GridView提供了两个预制列表,或者您能够构建本身的自定义网格。 当GridView检测到其内容太长而不适合渲染框时,它会自动滚动。
GridView摘要:
注意:显示二维列表时,重要的是单元格占用哪一行和一列(例如,它是“avocado”行的“calorie”列中的条目),请使用Table或DataTable。
GridView示例:
使用GridView.extent建立一个最大宽度为150像素的网格。
Dart code: main.dart,
Images: images
Pubspec: pubspec.yaml
// The images are saved with names pic1.jpg, pic2.jpg...pic30.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) { return new List<Container>.generate( count, (int index) => new Container(child: new Image.asset('images/pic${index+1}.jpg'))); } Widget buildGrid() { return new GridView.extent( maxCrossAxisExtent: 150.0, padding: const EdgeInsets.all(4.0), mainAxisSpacing: 4.0, crossAxisSpacing: 4.0, children: _buildGridTileList(30)); } class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: buildGrid(), ), ); } }
使用GridView.count在纵向模式下建立2个宽度的网格,在横向模式下建立3个宽度的网格。 标题是经过设置每一个GridTile的页脚属性建立的。
Dart code:来自Flutter Gallery的grid_list_demo.dart
ListView是一个相似列的小部件,它的内容对于其渲染框太长时会自动提供滚动。
ListView摘要:
ListView示例:
使用ListView显示使用ListTiles的业务列表。 分隔线将餐厅与餐厅分开。
Dart code: main.dart,
Icons: Icons class
Pubspec: pubspec.yaml
List<Widget> list = <Widget>[ new ListTile( title: new Text('CineArts at the Empire', style: new TextStyle(fontWeight: FontWeight.w500, fontSize: 20.0)), subtitle: new Text('85 W Portal Ave'), leading: new Icon( Icons.theaters, color: Colors.blue[500], ), ), new ListTile( title: new Text('The Castro Theater', style: new TextStyle(fontWeight: FontWeight.w500, fontSize: 20.0)), subtitle: new Text('429 Castro St'), leading: new Icon( Icons.theaters, color: Colors.blue[500], ), ), // ... // See the rest of the column defined on GitHub: // https://raw.githubusercontent.com/flutter/website/master/_includes/code/layout/listview/main.dart ]; class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return new Scaffold( // ... body: new Center( child: new ListView( children: list, ), ), ); } }
使用ListView显示特定Colors的Material Design面板中的颜色。
Dart代码:来自Flutter Gallery的colors_demo.dart
使用Stack来安排基础小部件顶部的小部件 - 一般是图像。 小部件能够彻底或部分重叠基础小部件。
Stack摘要:
Stack示例:
使用Stack叠加容器(在半透明的黑色背景上显示其文本),放置在Circle Avatar的顶部。Stack使用alignment属性和Alignments偏移文本。
Dart code: main.dart
Image: images
Pubspec: pubspec.yaml
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { var stack = new Stack( alignment: const Alignment(0.6, 0.6), children: [ new CircleAvatar( backgroundImage: new AssetImage('images/pic.jpg'), radius: 100.0, ), new Container( decoration: new BoxDecoration( color: Colors.black45, ), child: new Text( 'Mia B', style: new TextStyle( fontSize: 20.0, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ], ); // ... } }
使用Stack将渐变叠加到图像的顶部。 渐变确保工具栏的图标与图像不一样。
Dart代码:Flutter Gallery中的contacts_demo.dart
材料组件库中的卡片包含相关的信息块,能够由大多数任何小部件构成,但一般与ListTile一块儿使用。 卡片有一个孩子,但其孩子能够是支持多个孩子的列,行,列表,网格或其余小部件。 默认状况下,卡片将其大小缩小为0像素0。 您可使用SizedBox来限制卡的大小。
在Flutter中,一张卡片具备稍微圆润的角落和阴影,使其具备3D效果。 更改卡片的elevation属性可以让您控制投影效果。 例如,将标高设置为24.0,将卡片从视觉上抬离表面并使阴影变得更加分散。 有关支持的高程值的列表,请参见材料准则中的高程和阴影。 指定不支持的值将彻底禁用投影。
Card摘要:
卡片示例:
包含3个ListTiles并经过用SizedBox包装进行大小调整的卡片。 分隔符分隔第一个和第二个ListTiles。
Dart code: main.dart
Icons: Icons class
Pubspec: pubspec.yaml
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { var card = new SizedBox( height: 210.0, child: new Card( child: new Column( children: [ new ListTile( title: new Text('1625 Main Street', style: new TextStyle(fontWeight: FontWeight.w500)), subtitle: new Text('My City, CA 99984'), leading: new Icon( Icons.restaurant_menu, color: Colors.blue[500], ), ), new Divider(), new ListTile( title: new Text('(408) 555-1212', style: new TextStyle(fontWeight: FontWeight.w500)), leading: new Icon( Icons.contact_phone, color: Colors.blue[500], ), ), new ListTile( title: new Text('costa@example.com'), leading: new Icon( Icons.contact_mail, color: Colors.blue[500], ), ), ], ), ), ); //... }
包含图像和文字的卡片。
Flutter代码:来自Flutter Gallery的cards_demo.dart
使用ListTile是Material Components库中的一个专门的行小部件,用于建立包含最多3行文本和可选的前导和尾随图标的行。 ListTile在Card或ListView中最经常使用,但能够在别处使用。
ListTile摘要:
ListTile示例:
包含3个ListTiles的卡片。
Dart代码:查看卡片示例。
使用ListTile列出3个下拉按钮类型。
飞镖代码:来自Flutter Gallery的buttons_demo.dart
编写布局代码时如下资源可能会有所帮助。