面向 Web 开发者的 Flutter
了解如何将 Web 开发知识应用于构建 Flutter 应用。
本页面专为熟悉 HTML 和 CSS 排版应用 UI 的开发者编写。它将 HTML/CSS 代码片段映射为对应的 Flutter/Dart 代码。
Flutter 是一个用于构建跨平台应用的框架,使用 Dart 编程语言。要了解 Dart 编程与 JavaScript 编程之间的一些差异,请参阅 以 JavaScript 开发者身份学习 Dart。
设计 Web 布局与 Flutter 布局的一个根本区别在于,需要了解约束(constraints)如何工作,以及组件(widgets)是如何调整大小和定位的。要了解更多信息,请参阅 理解约束。
示例假设
-
HTML 文档以
<!DOCTYPE html>开头,并且所有 HTML 元素的 CSS 盒模型都设置为border-box,以与 Flutter 模型保持一致。css{ box-sizing: border-box; } -
在 Flutter 中,“Lorem ipsum”文本的默认样式由
bold24Roboto变量定义如下,以便简化语法dartTextStyle bold24Roboto = const TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, );
执行基本的布局操作
#以下示例展示了如何执行最常见的 UI 布局任务。
设置文本样式与对齐
#CSS 通过 font 和 color 属性处理的字体样式、大小及其他文本属性,在 Flutter 中是 Text 组件的 TextStyle 子属性。
对于 CSS 中用于对齐文本的 text-align 属性,Text 组件中有一个 textAlign 属性对应。
在 HTML 和 Flutter 中,子元素或组件默认都固定在左上角。
<div class="grey-box">
Lorem ipsum
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Georgia;
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: const Text(
'Lorem ipsum',
style: TextStyle(
fontFamily: 'Georgia',
fontSize: 24,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
);
设置背景颜色
#在 Flutter 中,您可以使用 Container 的 color 属性或 decoration 属性来设置背景颜色。但是,您不能同时提供两者,因为这可能会导致装饰(decoration)覆盖背景颜色。当背景为简单颜色时,应优先使用 color 属性。对于其他情况,例如渐变或图像,请使用 decoration 属性。
CSS 示例使用了与 Material 配色方案对应的十六进制颜色值。
<div class="grey-box">
Lorem ipsum
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Text(
'Lorem ipsum',
style: bold24Roboto,
),
);
final container = Container(
// grey box
width: 320,
height: 240,
decoration: BoxDecoration(
color: Colors.grey[300],
),
child: Text(
'Lorem ipsum',
style: bold24Roboto,
),
);
居中组件
#Center 组件可以将其子组件水平和垂直居中。
要在 CSS 中实现类似效果,父元素需使用 flex 或 table-cell 显示行为。本页示例展示了 flex 行为。
<div class="grey-box">
Lorem ipsum
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Center(
child: Text(
'Lorem ipsum',
style: bold24Roboto,
),
),
);
设置容器宽度
#要指定 Container 组件的宽度,请使用其 width 属性。这是一个固定宽度,与 CSS 中将容器宽度调整到最大值的 max-width 属性不同。若要在 Flutter 中模拟该效果,请使用 Container 的 constraints 属性。创建一个带有 minWidth 或 maxWidth 的新 BoxConstraints 组件。
对于嵌套容器,如果父容器宽度小于子容器宽度,子容器会自动调整自身大小以匹配父容器。
<div class="grey-box">
<div class="red-box">
Lorem ipsum
</div>
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
.red-box {
background-color: #ef5350; /* red 400 */
padding: 16px;
color: #ffffff;
width: 100%;
max-width: 240px;
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Center(
child: Container(
// red box
width: 240, // max-width is 240
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.red[400],
),
child: Text(
'Lorem ipsum',
style: bold24Roboto,
),
),
),
);
操作位置与大小
#以下示例展示了如何对组件位置、大小和背景执行更复杂的操作。
设置绝对定位
#默认情况下,组件相对于其父组件定位。
要为组件指定绝对位置(x-y 坐标),请将其嵌套在 Positioned 组件中,该组件进而嵌套在 Stack 组件中。
<div class="grey-box">
<div class="red-box">
Lorem ipsum
</div>
</div>
.grey-box {
position: relative;
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
}
.red-box {
background-color: #ef5350; /* red 400 */
padding: 16px;
color: #ffffff;
position: absolute;
top: 24px;
left: 24px;
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Stack(
children: [
Positioned(
// red box
left: 24,
top: 24,
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.red[400],
),
child: Text(
'Lorem ipsum',
style: bold24Roboto,
),
),
),
],
),
);
旋转组件
#要旋转组件,请将其嵌套在 Transform 组件中。使用 Transform 组件的 alignment 和 origin 属性分别以相对和绝对方式指定变换原点(支点)。
对于简单的 2D 旋转(即组件绕 Z 轴旋转),创建一个新的 Matrix4 恒等对象,并使用其 rotateZ() 方法以弧度(度数 × π / 180)指定旋转因子。
<div class="grey-box">
<div class="red-box">
Lorem ipsum
</div>
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
.red-box {
background-color: #ef5350; /* red 400 */
padding: 16px;
color: #ffffff;
transform: rotate(15deg);
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Center(
child: Transform(
alignment: Alignment.center,
transform: Matrix4.identity()..rotateZ(15 * 3.1415927 / 180),
child: Container(
// red box
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.red[400],
),
child: Text(
'Lorem ipsum',
style: bold24Roboto,
textAlign: TextAlign.center,
),
),
),
),
);
缩放组件
#要放大或缩小组件,请将其嵌套在 Transform 组件中。使用 Transform 组件的 alignment 和 origin 属性分别以相对或绝对方式指定变换原点(支点)。
对于沿 x 轴的简单缩放操作,创建一个新的 Matrix4 恒等对象,并使用其 scale() 方法指定缩放因子。
当您缩放父组件时,其子组件也会相应地进行缩放。
<div class="grey-box">
<div class="red-box">
Lorem ipsum
</div>
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
.red-box {
background-color: #ef5350; /* red 400 */
padding: 16px;
color: #ffffff;
transform: scale(1.5);
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Center(
child: Transform(
alignment: Alignment.center,
transform: Matrix4.identity()..scaleByDouble(1.5, 1.5, 1.5, 1.5),
child: Container(
// red box
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.red[400],
),
child: Text(
'Lorem ipsum',
style: bold24Roboto,
textAlign: TextAlign.center,
),
),
),
),
);
应用线性渐变
#要将线性渐变应用于组件背景,请将其嵌套在 Container 组件中。然后使用 Container 组件的 decoration 属性创建一个 BoxDecoration 对象,并使用 BoxDecoration 的 gradient 属性来转换背景填充。
渐变“角度”基于对齐 (x, y) 值
- 如果开始和结束的 x 值相等,则渐变为垂直 (0° | 180°)。
- 如果开始和结束的 y 值相等,则渐变为水平 (90° | 270°)。
垂直渐变
#<div class="grey-box">
<div class="red-box">
Lorem ipsum
</div>
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
.red-box {
padding: 16px;
color: #ffffff;
background: linear-gradient(180deg, #ef5350, rgba(0, 0, 0, 0) 80%);
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Center(
child: Container(
// red box
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment(0.0, 0.6),
colors: <Color>[
Color(0xffef5350),
Color(0x00ef5350),
],
),
),
padding: const EdgeInsets.all(16),
child: Text(
'Lorem ipsum',
style: bold24Roboto,
),
),
),
);
水平渐变
#<div class="grey-box">
<div class="red-box">
Lorem ipsum
</div>
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
.red-box {
padding: 16px;
color: #ffffff;
background: linear-gradient(90deg, #ef5350, rgba(0, 0, 0, 0) 80%);
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Center(
child: Container(
// red box
padding: const EdgeInsets.all(16),
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment(-1.0, 0.0),
end: Alignment(0.6, 0.0),
colors: <Color>[
Color(0xffef5350),
Color(0x00ef5350),
],
),
),
child: Text(
'Lorem ipsum',
style: bold24Roboto,
),
),
),
);
操作形状
#以下示例展示了如何制作和自定义形状。
圆角处理
#要对矩形形状进行圆角处理,请使用 BoxDecoration 对象的 borderRadius 属性。创建一个新的 BorderRadius 对象,指定每个角的圆角半径。
<div class="grey-box">
<div class="red-box">
Lorem ipsum
</div>
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
.red-box {
background-color: #ef5350; /* red 400 */
padding: 16px;
color: #ffffff;
border-radius: 8px;
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Center(
child: Container(
// red circle
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.red[400],
borderRadius: const BorderRadius.all(
Radius.circular(8),
),
),
child: Text(
'Lorem ipsum',
style: bold24Roboto,
),
),
),
);
添加盒阴影
#在 CSS 中,您可以使用 box-shadow 属性简写指定阴影偏移和模糊。此示例展示了两个属性如下的盒阴影:
xOffset: 0px, yOffset: 2px, blur: 4px, color: black @80% alphaxOffset: 0px, yOffset: 06px, blur: 20px, color: black @50% alpha
在 Flutter 中,每个属性和值都是单独指定的。使用 BoxDecoration 的 boxShadow 属性创建一个 BoxShadow 组件列表。您可以定义一个或多个 BoxShadow 组件,它们可以堆叠以自定义阴影深度、颜色等。
<div class="grey-box">
<div class="red-box">
Lorem ipsum
</div>
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
.red-box {
background-color: #ef5350; /* red 400 */
padding: 16px;
color: #ffffff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.8),
0 6px 20px rgba(0, 0, 0, 0.5);
}
final container = Container(
// grey box
width: 320,
height: 240,
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: Colors.grey[300],
),
child: Center(
child: Container(
// red box
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.red[400],
boxShadow: const <BoxShadow>[
BoxShadow(
color: Color(0xcc000000),
offset: Offset(0, 2),
blurRadius: 4,
),
BoxShadow(
color: Color(0x80000000),
offset: Offset(0, 6),
blurRadius: 20,
),
],
),
child: Text(
'Lorem ipsum',
style: bold24Roboto,
),
),
),
);
制作圆形与椭圆形
#在 CSS 中制作圆形需要变通方法,即对矩形的四个边应用 50% 的 border-radius,尽管也有 基础形状 可供使用。
虽然这种方法在 BoxDecoration 的 borderRadius 属性中也受支持,但 Flutter 为此专门提供了带有 BoxShape 枚举 的 shape 属性。
<div class="grey-box">
<div class="red-circle">
Lorem ipsum
</div>
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
.red-circle {
background-color: #ef5350; /* red 400 */
padding: 16px;
color: #ffffff;
text-align: center;
width: 160px;
height: 160px;
border-radius: 50%;
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Center(
child: Container(
// red circle
decoration: BoxDecoration(
color: Colors.red[400],
shape: BoxShape.circle,
),
padding: const EdgeInsets.all(16),
width: 160,
height: 160,
child: Text(
'Lorem ipsum',
style: bold24Roboto,
textAlign: TextAlign.center,
),
),
),
);
操作文本
#以下示例展示了如何指定字体和其他文本属性。它们还展示了如何转换文本字符串、自定义间距以及创建摘要。
调整文本间距
#在 CSS 中,您可以通过为 letter-spacing 和 word-spacing 属性提供长度值来指定每个字母或单词之间的空白量。空间量可以使用 px、pt、cm、em 等单位。
在 Flutter 中,您将空白指定为逻辑像素(允许负值),并赋给 Text 组件子项 TextStyle 的 letterSpacing 和 wordSpacing 属性。
<div class="grey-box">
<div class="red-box">
Lorem ipsum
</div>
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
.red-box {
background-color: #ef5350; /* red 400 */
padding: 16px;
color: #ffffff;
letter-spacing: 4px;
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Center(
child: Container(
// red box
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.red[400],
),
child: const Text(
'Lorem ipsum',
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.w900,
letterSpacing: 4,
),
),
),
),
);
进行行内格式更改
#Text 组件允许您显示带有特定格式的文本。要显示使用多种样式的文本(在此示例中,单个词带有强调),请改用 RichText 组件。其 text 属性可以指定一个或多个可以分别设置样式的 TextSpan 对象。
在以下示例中,“Lorem”位于具有默认(继承)文本样式的 TextSpan 中,“ipsum”则位于具有自定义样式的单独 TextSpan 中。
<div class="grey-box">
<div class="red-box">
Lorem <em>ipsum</em>
</div>
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
.red-box {
background-color: #ef5350; /* red 400 */
padding: 16px;
color: #ffffff;
}
.red-box em {
font: 300 48px Roboto;
font-style: italic;
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Center(
child: Container(
// red box
decoration: BoxDecoration(
color: Colors.red[400],
),
padding: const EdgeInsets.all(16),
child: RichText(
text: TextSpan(
style: bold24Roboto,
children: const <TextSpan>[
TextSpan(text: 'Lorem '),
TextSpan(
text: 'ipsum',
style: TextStyle(
fontWeight: FontWeight.w300,
fontStyle: FontStyle.italic,
fontSize: 48,
),
),
],
),
),
),
),
);
创建文本摘要
#摘要(Excerpt)显示段落的初始行,并处理溢出文本,通常使用省略号。
在 Flutter 中,使用 Text 组件的 maxLines 属性来指定摘要中包含的行数,并使用 overflow 属性来处理溢出的文本。
<div class="grey-box">
<div class="red-box">
Lorem ipsum dolor sit amet, consec etur
</div>
</div>
.grey-box {
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 900 24px Roboto;
display: flex;
align-items: center;
justify-content: center;
}
.red-box {
background-color: #ef5350; /* red 400 */
padding: 16px;
color: #ffffff;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
final container = Container(
// grey box
width: 320,
height: 240,
color: Colors.grey[300],
child: Center(
child: Container(
// red box
decoration: BoxDecoration(
color: Colors.red[400],
),
padding: const EdgeInsets.all(16),
child: Text(
'Lorem ipsum dolor sit amet, consec etur',
style: bold24Roboto,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
),
);