1. 簡介
Material Design 元件 (MDC) 可協助開發人員實作質感設計。MDC 是由 Google 工程師和使用者體驗設計師團隊打造,提供數十種精美且功能豐富的 UI 元件,適用於 Android、iOS、網頁和 Flutter.material.io/develop |
你現在可以使用 Material Flutter 自訂應用程式展現獨特風格Material Design 最近的擴展功能為設計人員和開發人員提供更多彈性,以呈現產品的品牌。
在程式碼研究室 (MDC-101 和 MDC-102) 中,您使用了 Material Flutter 來建構名為 Shrine 的應用程式基本資訊,這是一款販售服飾和居家用品的電子商務應用程式。這個應用程式的使用者流程是從登入畫面開始,然後將使用者導向到顯示產品的主畫面。
建構項目
在本程式碼研究室中,您將使用以下項目自訂 Shrine 應用程式:
- 顏色
- 字體排版
- 海拔高度
- 圖案
- 版面配置
Android | iOS |
本程式碼研究室中的 Material Flutter 元件和子系統
- 主題
- 字體排版
- 海拔高度
- 圖片清單
針對 Flutter 開發經驗,您會給予什麼評價?
2. 設定 Flutter 開發環境
您需要使用兩項軟體:Flutter SDK 和編輯器。
您可以使用下列任一裝置執行程式碼研究室:
- 將實體 Android 或 iOS 裝置接上電腦,並設為開發人員模式。
- iOS 模擬器 (需要安裝 Xcode 工具)。
- Android Emulator (需要在 Android Studio 中設定)。
- 瀏覽器 (必須使用 Chrome 進行偵錯)。
- 下載 Windows、Linux 或 macOS 桌面應用程式。您必須在要部署的平台上進行開發。因此,如果您想要開發 Windows 電腦版應用程式,就必須在 Windows 上進行開發,以便存取適當的建構鏈結。如要進一步瞭解作業系統的特定需求,請參閱 docs.flutter.dev/desktop。
3. 下載程式碼研究室的範例應用程式
您使用的是 MDC-102 版本嗎?
完成 MDC-102 後,您的程式碼應該就可以用於本程式碼研究室。跳至步驟:變更顏色。
還是從頭開始?
下載程式碼研究室入門應用程式
範例應用程式位於 material-components-flutter-codelabs-103-starter_and_102-complete/mdc_100_series
目錄中。
...或是從 GitHub 複製檔案
如要從 GitHub 複製本程式碼研究室,請執行下列指令:
git clone https://github.com/material-components/material-components-flutter-codelabs.git cd material-components-flutter-codelabs/mdc_100_series git checkout 103-starter_and_102-complete
開啟專案並執行應用程式
大功告成!您應該會在裝置上看到先前程式碼研究室的 Shrine 登入頁面。
Android | iOS |
點選「下一步」即可查看產品頁面
Android | iOS |
4. 變更色彩
我們製作了代表神社品牌的色彩配置,而設計人員希望您能在整個 Shrine 應用程式中導入這個色彩配置
首先,請將這些顏色匯入專案。
建立 colors.dart
在 lib
中建立名為 colors.dart
的新 dart 檔案。匯入 material.dart
並新增 const Color
值:
import 'package:flutter/material.dart';
const kShrinePink50 = Color(0xFFFEEAE6);
const kShrinePink100 = Color(0xFFFEDBD0);
const kShrinePink300 = Color(0xFFFBB8AC);
const kShrinePink400 = Color(0xFFEAA4A4);
const kShrineBrown900 = Color(0xFF442B2D);
const kShrineErrorRed = Color(0xFFC5032B);
const kShrineSurfaceWhite = Color(0xFFFFFBFA);
const kShrineBackgroundWhite = Colors.white;
自訂調色盤
這個顏色主題是由設計人員使用自訂顏色建立 (如下圖所示)。當中包含從神社品牌挑選的色彩,並套用至 Material 主題編輯器,這種編輯器的色彩進一步擴大,呈現出更全面的調色盤。(這些顏色並非來自 2014 年 Material 調色盤)。
Material Design 主題編輯器已將這些顏色整理成以數字標示的色調,包括每種顏色標籤 50、100、200、.... 到 900。神社只使用粉色色的 50、100 和 300 層,以及棕色樣本中 900 的陰影。
小工具的每個彩色參數都會對應到這些配置中的顏色。例如,文字欄位在主動接收輸入內容時,裝飾的顏色應為主題的「Primary」顏色。如果顏色不透明 (很容易在背景上可見),請改用其他顏色。
現在,我們有了要使用的顏色,就可以將這些顏色套用至 UI。方法是設定 ThemeData 小工具的值,並套用至小工具階層頂端的 MaterialApp 例項。
自訂 ThemeData.light()
Flutter 含有一些內建主題。其中之一是淺色主題。我們不會從頭開始製作 ThemeData 小工具,而是會複製淺色主題並變更值,以便為應用程式自訂主題。
讓我們在 app.dart.
中匯入 colors.dart
import 'colors.dart';
接著,將以下內容新增至 ShrineApp 類別的「外部」範圍:
// TODO: Build a Shrine Theme (103)
final ThemeData _kShrineTheme = _buildShrineTheme();
ThemeData _buildShrineTheme() {
final ThemeData base = ThemeData.light(useMaterial3: true);
return base.copyWith(
colorScheme: base.colorScheme.copyWith(
primary: kShrinePink100,
onPrimary: kShrineBrown900,
secondary: kShrineBrown900,
error: kShrineErrorRed,
),
// TODO: Add the text themes (103)
// TODO: Decorate the inputs (103)
);
}
現在,將 ShrineApp build()
函式結尾處的 theme:
(在 MaterialApp 小工具中) 設為新的主題:
// TODO: Customize the theme (103)
theme: _kShrineTheme, // New code
儲存專案。登入畫面現在應如下所示:
Android | iOS |
5. 修改字體排版和標籤樣式
除了顏色改變之外,設計人員也為使用者提供了特定的字體排版。Flutter 的 ThemeData 包含 3 個文字主題。每個文字主題都是一組文字樣式,例如「廣告標題」和「title」我們會為應用程式採用幾種樣式,並變更部分值。
自訂文字主題
如要將字型匯入專案,必須將這些字型新增至 pubspec.yaml 檔案。
在 pubspec.yaml 中,將以下內容加到 flutter:
標記後方:
# TODO: Insert Fonts (103)
fonts:
- family: Rubik
fonts:
- asset: fonts/Rubik-Regular.ttf
- asset: fonts/Rubik-Medium.ttf
weight: 500
現在您可以存取及使用 Rubik 字型。
排解 pubspec 檔案問題
如果您剪下並貼上上述宣告,執行 pub get 時可能會發生錯誤。如果發生錯誤,請先移除開頭的空白字元,然後使用 2 個空格縮排來取代該空白字元。(前兩個空格
fonts:
,前面有四個空格
family: Rubik
等。)
如果看到「這裡不允許對應值」,請檢查有問題的行縮排,以及該行上方的縮排。
在 login.dart
中,在 Column()
內變更以下內容:
Column(
children: <Widget>[
Image.asset('assets/diamond.png'),
const SizedBox(height: 16.0),
Text(
'SHRINE',
style: Theme.of(context).textTheme.headlineSmall,
),
],
)
在 app.dart
的 _buildShrineTheme()
後方,新增以下內容:
// TODO: Build a Shrine Text Theme (103)
TextTheme _buildShrineTextTheme(TextTheme base) {
return base
.copyWith(
headlineSmall: base.headlineSmall!.copyWith(
fontWeight: FontWeight.w500,
),
titleLarge: base.titleLarge!.copyWith(
fontSize: 18.0,
),
bodySmall: base.bodySmall!.copyWith(
fontWeight: FontWeight.w400,
fontSize: 14.0,
),
bodyLarge: base.bodyLarge!.copyWith(
fontWeight: FontWeight.w500,
fontSize: 16.0,
),
)
.apply(
fontFamily: 'Rubik',
displayColor: kShrineBrown900,
bodyColor: kShrineBrown900,
);
}
這項操作會採用 TextTheme,並變更廣告標題、標題和說明的外觀。
以這種方式套用 fontFamily
,只會將變更套用到 copyWith()
中指定的字體排版比例值 (廣告標題、標題、說明文字)。
針對部分字型,我們會設定自訂 fontWeight,以 100 為單位遞增:w500 (500 粗細),對應中 , w400 對應到一般。
使用新的文字內容
發生錯誤後,將下列主題新增至 _buildShrineTheme
:
// TODO: Add the text themes (103)
textTheme: _buildShrineTextTheme(base.textTheme),
textSelectionTheme: const TextSelectionThemeData(
selectionColor: kShrinePink100,
),
儲存專案。此外,由於我們修改了字型,這次也請重新啟動應用程式 (也稱為「Hot Restart」)。
Android | iOS |
登入畫面和主畫面上的文字看起來不太一樣:有些文字使用 Rubik 字型,而其他文字則是以棕色顯示,而非黑色或白色。圖示也會顯示為棕色。
縮小文字
標籤太大。
在 home.dart
中,變更最內部資料欄的 children:
:
// TODO: Change innermost Column (103)
children: <Widget>[
// TODO: Handle overflowing labels (103)
Text(
product.name,
style: theme.textTheme.button,
softWrap: false,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
const SizedBox(height: 4.0),
Text(
formatter.format(product.price),
style: theme.textTheme.bodySmall,
),
// End new code
],
將文字置中並置於中央
我們希望將標籤置中,並將文字對齊每張資訊卡底部,而非每張圖片的底部。
將標籤移至主軸的結尾 (底部),並將標籤變更為置中:
// TODO: Align labels to the bottom and center (103)
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
儲存專案。
Android | iOS |
這樣看起來好多了。
設定文字欄位的主題
您也可以使用 InputDecorationTheme 設定文字欄位的裝飾主題。
在 app.dart
的 _buildShrineTheme()
方法中指定 inputDecorationTheme:
值:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
),
目前文字欄位有 filled
裝飾。讓我們將其移除。移除 filled
並指定 inputDecorationTheme
,文字欄位就會有外框樣式。
在 login.dart
中,移除 filled: true
值:
// Remove filled: true values (103)
TextField(
controller: _usernameController,
decoration: const InputDecoration(
// Removed filled: true
labelText: 'Username',
),
),
const SizedBox(height: 12.0),
TextField(
controller: _passwordController,
decoration: const InputDecoration(
// Removed filled: true
labelText: 'Password',
),
obscureText: true,
),
熱重新啟動。如果 [使用者名稱] 欄位處於有效狀態 (輸入時),您的登入畫面看起來應該會像這樣:
Android | iOS |
在文字欄位中輸入文字 - 邊框和浮動標籤會以主要顏色顯示。然而,這種情況並不容易。無法區分像素色彩對比不足的使用者。(詳情請參閱 Material 指南的顏色與無障礙功能相關文章)。
在 app.dart
中,在 inputDecorationTheme:
下指定 focusedBorder:
:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
),
接著,在 inputDecorationTheme:
下指定 floatingLabelStyle:
:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
floatingLabelStyle: TextStyle(
color: kShrineBrown900,
),
),
最後,將「取消」按鈕設為使用次要顏色,而非主要顏色來提升對比。
TextButton(
child: const Text('CANCEL'),
onPressed: () {
_usernameController.clear();
_passwordController.clear();
},
style: TextButton.styleFrom(
primary: Theme.of(context).colorScheme.secondary,
),
),
儲存專案。
Android | iOS |
6. 調整高度
您已為頁面設定符合 Shrine 的特定顏色和字體樣式,現在要調整高度。
變更「繼續」按鈕的高度
ElevatedButton
的預設高度為 2。讓我們提高目標。
在 login.dart
中,將 style:
值新增至 NEXT ElevatedButton:
ElevatedButton(
child: const Text('NEXT'),
onPressed: () {
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
foregroundColor: kShrineBrown900,
backgroundColor: kShrinePink100,
elevation: 8.0,
),
),
儲存專案。
Android | iOS |
調整資訊卡高度
目前,資訊卡應該位於網站導覽頁面旁邊的白色表面上。
在 home.dart
中,將 elevation:
值新增至資訊卡:
// TODO: Adjust card heights (103)
elevation: 0.0,
儲存專案。
Android | iOS |
移除資訊卡下的陰影。
7. 新增形狀
神社擁有酷炫的幾何風格,以八角或長方形設計元素。讓我們在主畫面的資訊卡以及登入畫面上的文字欄位和按鈕,實作該形狀樣式。
變更登入畫面上的文字欄位圖案
在 app.dart
中,匯入下列檔案:
import 'supplemental/cut_corners_border.dart';
同樣在 app.dart
中,請修改文字欄位裝飾主題,以使用裁剪角落的邊框:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: CutCornersBorder(),
focusedBorder: CutCornersBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
floatingLabelStyle: TextStyle(
color: kShrineBrown900,
),
),
變更登入畫面上的按鈕形狀
在 login.dart
中,為「CANCEL」按鈕加上斜角矩形邊框:
TextButton(
child: const Text('CANCEL'),
onPressed: () {
_usernameController.clear();
_passwordController.clear();
},
style: TextButton.styleFrom(
foregroundColor: kShrineBrown900,
shape: const BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(7.0)),
),
),
),
TextButton 沒有可見的形狀,為什麼要新增邊框形狀?因此,漣漪效果動畫輕觸時會與相同的形狀繫結。
現在,在「Next」按鈕中加入相同的形狀:
ElevatedButton(
child: const Text('NEXT'),
onPressed: () {
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
foregroundColor: kShrineBrown900,
backgroundColor: kShrinePink100,
elevation: 8.0,
shape: const BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(7.0)),
),
),
),
如要變更所有按鈕的形狀,也可以在 app.dart
中使用 elevatedButtonTheme
或 textButtonTheme
。這已是學員的挑戰!
熱重新啟動。
Android | iOS |
8. 變更版面配置
接下來,我們要變更版面配置,以不同的顯示比例和大小顯示資訊卡,讓每張資訊卡看起來與其他資訊卡不同。
將 GridView 替換為 AsymmetricView
我們已經為非對稱版面配置編寫檔案。
在 home.dart
中新增以下匯入項目:
import 'supplemental/asymmetric_view.dart';
刪除 _buildGridCards
並替換 body
:
body: AsymmetricView(
products: ProductsRepository.loadProducts(Category.all),
),
儲存專案。
Android | iOS |
現在,產品會以編織紋風格水平捲動。
9. 試試其他主題 (選用)
顏色是展現品牌精神的有效方法,稍微改變顏色則可提升使用者體驗。如要測試這項功能,我們來看看當品牌的色彩配置略有不同時,神殿的樣子。
修改顏色
在 colors.dart
中新增下列顏色:
const kShrinePurple = Color(0xFF5D1049);
在 app.dart
中,將 _buildShrineTheme()
函式變更為以下內容:
ThemeData _buildShrineTheme() {
final ThemeData base = ThemeData.light();
return base.copyWith(
colorScheme: base.colorScheme.copyWith(
primary: kShrinePurple,
secondary: kShrinePurple,
error: kShrineErrorRed,
),
scaffoldBackgroundColor: kShrineSurfaceWhite,
textSelectionTheme: const TextSelectionThemeData(
selectionColor: kShrinePurple,
),
appBarTheme: const AppBarTheme(
foregroundColor: kShrineBrown900,
backgroundColor: kShrinePink100,
),
inputDecorationTheme: const InputDecorationTheme(
border: CutCornersBorder(),
focusedBorder: CutCornersBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrinePurple,
),
),
floatingLabelStyle: TextStyle(
color: kShrinePurple,
),
),
);
}
熱重新啟動。這時應該會顯示新主題。
Android | iOS |
Android | iOS |
結果非常不同!讓我們把 app.dart's
_buildShrineTheme
還原為這個步驟之前的項目。或下載 104 的範例程式碼。
10. 恭喜!
您現在已建立與設計人員設計規格類似的應用程式。
後續步驟
您已使用下列 Material Flutter:主題、字體排版、高度和形狀。您可以在 Material Flutter 程式庫中探索更多元件和子系統。
深入瞭解 supplemental
目錄中的檔案,瞭解我們如何水平捲動非對稱版面配置格線。
如果您規劃的應用程式設計含有沒有程式庫元件的元素,該怎麼辦?在 MDC-104:Material 進階元件中,我們示範如何使用 Material Flutter 程式庫建立自訂元件,達到想要的外觀。