面向 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,
),
),
),
);