给 Web 开发者的 Flutter 指南
本文是为那些熟悉用 HTML 与 CSS 语法来管理应用页面中元素的开发者准备的。本文会将 HTML/CSS 代码片段替换为等价的 Flutter/Dart 代码。
Flutter 是一个用于构建跨平台应用的框架,它使用 Dart 编程语言。要了解 Dart 编程语言与 Javascript 编程语言的异同,请参考文档 给 JavaScript 开发者的 Dart 编程语言指南。
在 Web 和 Flutter 的布局基础条件中, 布局限制、widget 的大小确定和定位 是重要的区别之一。想要了解更多,你可以阅读 深入理解 Flutter 布局约束。
以下的示例基于如下假设:
-
HTML 文件以
<!DOCTYPE html>
开头,且为了与 Flutter 模型保持一致,所有 HTML 元素的 CSS 盒模型被设置为border-box
。css{ box-sizing: border-box; }
-
在 Flutter 中,为了保持语法简洁, "Lorem ipsum" 文本的默认样式由如下
bold24Roboto
变量定义:dartTextStyle bold24Roboto = const TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, );
执行基础布局操作
#以下示例将向你展示如何执行最常见的 UI 布局操作。
文本样式与对齐
#CSS 所处理的字体样式、大小以及其他文本属性,都是一个 Text
widget 子元素 TextStyle
中单独的属性。
Text
widget 中的 textAlign 属性与 CSS 中的
text-align 属性作用相同,用来控制文本的对齐方向。
在 HTML 和 Flutter 中,子元素或者 widget 的位置都默认在左上方。
<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
的
decoration
或者 color
属性来设置背景颜色。但是,你不能同时设置这两个属性,这有可能导致 decoration
覆盖掉 color
。当背景是简单的颜色时,应首选 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
widget 可以将它的子 widget 同时以水平和垂直方向居中。
要用 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
widget 的宽度,请使用它的 width
属性。与 CSS 中的 max-width 属性用于指定容器可调整的宽度最大值不同的是,这里指定的是一个固定宽度。要在 Flutter 中模拟该效果,可以使用 Container 的 constraints
属性。新建一个带有 minWidth
和 maxWidth
属性的 BoxConstraints
widget。
对嵌套的 Container 来说,如果其父元素宽度小于子元素宽度,则子元素会调整尺寸以匹配父元素大小。
<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,
),
),
),
);
操控位置与大小
#以下示例将展示如何对 widget 的位置、大小以及背景进行更复杂的操作。
设置绝对位置
#默认情况下,widget 相对于其父元素定位。
想要通过 x-y 坐标指定一个 widget 的绝对位置,可以把它放在一个 Positioned
widget 中,而 Positioned
则需被放在一个 Stack
widget 中。
<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,
),
),
),
],
),
);
旋转元素
#想要旋转一个 widget,请将它放在 Transform
widget 中。使用 Transform
widget 的 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,
),
),
),
),
);
缩放元素
#想要缩放一个 widget,请同样将它放在一个 Transform
widget 中。使用 Transform
widget 的 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()..scale(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,
),
),
),
),
);
应用线性变换
#想要将线性颜色渐变在 widget 的背景上应用,请将它嵌套在一个 Container
widget 中。接着将一个 BoxDecoration
对象传递至 Container
的 decoration
,然后使用 BoxDecoration
的 gradient
属性来变换背景填充内容。
变换「角度」基于 Alignment (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,
),
),
),
);
为盒子添加阴影 (box shadows)
#在 CSS 中你可以通过 box-shadow 属性快速指定阴影偏移与模糊范围。本例展示了两个盒阴影的属性设置:
xOffset: 0px, yOffset: 2px, blur: 4px, color: black @80% alpha
xOffset: 0px, yOffset: 06x, blur: 20px, color: black @50% alpha
在 Flutter 中,每个属性与其取值都是单独指定的。请使用 BoxDecoration 的 boxShadow
属性来生成一系列 BoxShadow
widget。你可以定义一个或多个 BoxShadow
widget,这些 widget 共同用于设置阴影深度、颜色等等。
<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 中有 基础图形,用 CSS 生成圆可以用一个变通方案,即将矩形的四边 border-radius 均设成 50%。
虽然 BoxDecoration
的 borderRadius
属性支持这样设置,
Flutter 提供了一个 shape
属性用于实现同样的目的,它的类型是 BoxShape
枚举。
<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
widget 的 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
widget 允许你展示同一类样式的文本。为了展现具有多种样式(本例中,是一个带重音的单词)的文本,你需要改用 RichText
widget。它的 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,
),
),
],
),
),
),
),
);
生成文本摘要
#一个摘要会展示一个段落中文本的初始行内容,并常用省略号处理溢出的文本内容。
在 Flutter 中,你可以使用 Text
widget 的
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,
),
),
),
);
除非另有说明,本文档之所提及适用于 Flutter 的最新稳定版本,本页面最后更新时间: 2024-11-02。 查看文档源码 或者 为本页面内容提出建议。