[译] MDC-102 Flutter:Material 结构和布局(Flutter)
- 原文地址:MDC-102 Flutter: Material Structure and Layout (Flutter)
- 原文作者:codelabs.developers.google.com
- 譯文出自:掘金翻譯計劃
- 本文永久鏈接:github.com/xitu/gold-m…
- 譯者:DevMcryYu
- 校對者:Rickon
MDC-102 Flutter:Material 結構和布局(Flutter)
1. 介紹
Material Components(MDC)幫助開發者實現 Material Design。MDC 由谷歌團隊的工程師和 UX 設計師創造,為 Android、iOS、Web 和 Flutter 提供很多美觀實用的 UI 組件。material.io/develop
在教程 MDC-101 中,你使用了兩個 Material 組件:文本框和墨水波紋效果的按鈕來構建一個登陸頁面。現在讓我們通過添加導航、結構和數據來拓展應用。
你將要構建
在本教程中,你將為 Shrine —— 一個銷售服裝和家居用品的電子商務應用程序構建一個主頁面。它將含有:
- 一個位于頂部的應用欄
- 一個由產品填充的網格列表
這是四篇教程里的第二篇,它將引導你為 Shrine 的產品構建應用程序。我們建議你按照教程的順序一步一步地編寫你的代碼。
相關的教程可以在以下位置找到:
- MDC-101: Material Components(MDC)基礎
- MDC-103: Material Design Theming 的顏色、形狀、高度和類型
- MDC-104: Material Design 高級組件。
到 MDC-104 的最后,你將會構建一個像這樣的應用:
將要用到的 MDC 組件
- 頂部應用欄(Top app bar)
- 網格(Grid)
- 卡片(Card)
本教程中,你將使用 MDC-Flutter 提供的默認組件。你將會在 MDC-103: Material Design Theming 的顏色、形狀、高度和類型中學習如何定制它們。
你將需要
- Flutter SDK
- 安裝好 Flutter 插件的 Android Studio,或者你喜歡的代碼編輯器
- 示例代碼
要在 iOS 上構建和運行 Flutter 應用程序,你需要滿足以下要求:
- 運行 macOS 的計算機
- Xcode 9 或更新版本
- iOS 模擬器,或者 iOS 物理設備
要在 Android 上構建和運行 Flutter 應用程序,你需要滿足以下要求:
- 運行 macOS、Windows 或 Linux 的計算機
- Android Studio
- Android 模擬器(隨 Android Studio 一起提供)或 Android 物理設備
2. 安裝 Flutter 環境
前提條件
要開始使用 Flutter 開發移動應用程序,你需要:
- Flutter SDK
- 裝有 Flutter 插件的 IntelliJ IDE,或者你喜歡的代碼編輯器
Flutter 的 IDE 工具適用于 Android Studio、IntelliJ IDEA Community(免費)和 IntelliJ IDEA Ultimate。
要在 iOS 上構建和運行 Flutter 應用程序,你需要滿足以下要求:- 運行 macOS 的計算機
- Xcode 9 或更新版本
- iOS 模擬器,或者 iOS 物理設備
- 運行 macOS、Windows 或者 Linux 的計算機
- Android Studio
- Android 模擬器(隨 Android Studio 一起提供)或 Android 物理設備
獲取詳細的 Flutter 安裝信息
重要提示:如果連接到計算機的 Android 手機上出現“允許 USB 調試”對話框,請啟用始終允許從此計算機選項,然后單擊確定。
在繼續本教程之前,請確保你的 SDK 處于正確的狀態。如果之前安裝過 Flutter,則使用 flutter upgrade 來確保 SDK 處于最新版本。
flutter upgrade 復制代碼運行 flutter upgrade 將自動運行 flutter doctor。如果這是首次安裝 Flutter 且不需升級,那么請手動運行 flutter doctor。查看顯示的所有檢查標記;這將會下載你需要的任何缺少的 SDK 文件,并確保你的計算機配置無誤以進行 Flutter 的開發。
flutter doctor 復制代碼3. 下載教程初始應用程序
從 MDC-101 繼續?
如果你完成了 MDC-101,那么本教程所需代碼應該已經準備就緒,跳轉到 添加應用欄 步驟。
從頭開始?
下載初始應用程序
下載初始程序
此入門程序位于 material-components-flutter-codelabs-102-starter_and_101-complete/mdc_100_series 目錄中。
...或者從 GitHub 克隆它
要從 GitHub 克隆此項目,請運行以下命令:
git clone https://github.com/material-components/material-components-flutter-codelabs.git cd material-components-flutter-codelabs git checkout 102-starter_and_101-complete 復制代碼更多幫助:從 GitHub 上克隆存儲庫
正確的分支
教程 MDC-101 到 104 連續構建。所以當你完成 102 的代碼后,它將變成 103 教程的初始代碼!代碼被分成不同的分支,你可以使用以下命令將它們全部列出:
git branch --list
要查看完整代碼,請切換到 103-starter_and_102-complete 分支。
建立你的項目
以下步驟默認你使用的是 Android Studio (IntelliJ)。
創建項目
在終端中,導航到 material-components-flutter-codelabs
運行 flutter create mdc_100_series
打開項目
打開 Android Studio。
如果你看到歡迎頁面,單擊 打開已有的 Android Studio 項目。
在構建項目一次之前,你可以忽略在分析中見到的任何錯誤。
提示:確保你已安裝 Flutter 和 Dart 插件。
運行初始程序
以下步驟默認你在 Android 模擬器或設備上進行測試。你也可以在 iOS 模擬器或設備上進行,只要你安裝了 Xcode。
如果 Android 模擬器尚未運行,請選擇 Tools -> Android -> AVD Manager 來創建您設備并啟動模擬器。如果 AVD 已存在,你可以直接在 IntelliJ 的設備選擇器中啟動模擬器,如下一步所示。
(對于 iOS 模擬器,如果它尚未運行,通過選擇 Flutter Device Selection -> Open iOS Simulator 來在你的開發設備上啟動它。)
- 在你的編輯器窗口頂部尋找 Flutter Device Selection 下拉菜單,然后選擇設備(例如,iPhone SE / Android SDK built for )。
- 點擊運行圖標()。
如果你無法成功運行此應用程序,停下來解決你的開發環境問題。嘗試導航到 material-components-flutter-codelabs;如果你在終端中下載 .zip 文件,導航到 material-components-flutter-codelabs-... 然后運行 flutter create mdc_100_series。
成功!Shrine 的初始登陸代碼應該在你的模擬器中運行了。你可以看到 Shrine 的 logo 和它下面的名稱 "Shrine"。
現在登錄頁面看起來不錯,讓我們用一些產品來填充應用。
4. 添加頂部應用欄
當登陸頁面消失時主頁面將出現并顯示“你做到了!”。這很棒!但是我們的用戶不知道能做什么操作,也不知道現在位于應用何處,為了解決這個問題,是時候添加導航了。
導航 是指允許用戶在應用中移動的組件、交互、視覺提示和信息結構。它使得內容和功能更加注目,任務也因此易于完成。
在 Material 指南中了解更多有關導航的信息。
Material Design 提供確保高度可用性的導航模式,其中最注目的組件就是頂部應用欄。
你可以將頂部應用欄當作 iOS 中的“導航欄”,或者簡單看成一個 “App Bar” 或 “Header”。
要提供導航并讓用戶快速訪問其他操作,讓我們添加一個頂部應用欄。
添加應用欄部件
在 home.dart 中,將應用欄添加到 Scaffold 中:
return Scaffold(// TODO: 添加應用欄(102)appBar: AppBar(// TODO: 添加按鈕和標題(102)), 復制代碼將 AppBar 添加到 Scaffold 的 appBar: 字段位置,為了我們完美的布局,讓應用欄保持在頁面的頂部或底部。
Scaffold 在中是一個重要的部件。它為像抽屜、snack bar 和 bottom sheet 等各種常見 Material 組件提供方便的 API。它甚至可以幫助布置一個 Floating Action Button。
在 Flutter 文檔中了解更多有關 Scaffold 的信息。
保存項目,當 Shrine 應用更新后,單擊 Next 來查看主屏幕。
應用欄看起來不錯,但它還需要一個標題。
如果應用沒有更新,再次單擊 “Play” 按鈕,或者點擊 “Play” 后的 “Stop”。
添加文本部件
在 home.dart 中,給應用欄添加一個標題:
// TODO: 添加應用欄(102) appBar: AppBar(// TODO: 添加按鈕和標題(102)title: Text('SHRINE'),// TODO:添加后續按鈕(102) 復制代碼保存項目。
到目前為止,你應該已經注意到我們所說的“平臺差異”了。Material 明白 Android、iOS、Web 各平臺都有差異。用戶對他們有不同的期望。舉例來說,在 iOS 里標題幾乎總是居中的,這是 UIKit 提供的默認配置。在 Android 上標題是左對齊的。所以如果你使用的是 Android 模擬器或設備,那么標題應該位于左側,對于 iOS 模擬器和設備而言,它應該是居中的。
了解更多信息,請查參閱有關跨平臺適配的 Material 文章。
許多應用欄在標題旁邊都設有按鈕,讓我們在應用中添加一個菜單圖標。
添加位于首部的圖標按鈕
還是在 home.dart 中,在 AppBar 的 leading 字段設置一個圖標按鈕:(放在 title: 字段前,按照部件從首到尾的順序):
return Scaffold(appBar: AppBar(// TODO: 添加按鈕和標題(102)leading: IconButton(icon: Icon(Icons.menu,semanticLabel: 'menu',),onPressed: () {print('Menu button');},), 復制代碼保存項目。
菜單圖標(也被稱作“漢堡包”)會在你期望的位置顯示出來。
IconButton 類是在你的應用里引入 Material 圖標的快捷方式。它有一個 Icon 部件。 Flutter 在 Icons 類里有整套的圖標。它會根據字符串常量的映射自動導入圖標。
在 Flutter 文檔中了解更多有關 Icons 類的信息。有關 Icon 部件的信息請閱讀這個 Flutter 文檔。
你也可以在標題尾部添加按鈕。在 Flutter 中,它們被稱為 "action"。
Leading(首部) 和 trailing(尾部) 是表達方向的術語,指的是與語言無關的文本行的開頭和結尾。當使用一個像英語這樣的 LTR(左到右)語言時, leading 意味著 左側 而 trailing 代表著 右側。在像阿拉伯語這樣的 RTL(右到左)語言時, leading 意味著 右側 而 trailing 代表著 左側。
了解 UI 鏡像的更多信息,請參閱 雙向性 Material Design 準則。
添加 action
還有兩個 IconButton 的空間。
在 AppBar 實例中的標題后面添加它們:
// TODO: 添加尾部按鈕(102) actions: <Widget>[IconButton(icon: Icon(Icons.search,semanticLabel: 'search',),onPressed: () {print('Search button');},),IconButton(icon: Icon(Icons.tune,semanticLabel: 'filter',),onPressed: () {print('Filter button');},), ], 復制代碼保存你的項目。你的主屏幕看起來應該像這樣:
現在這個應用在左側有一個按鈕、一個標題,右側還有兩個 action。應用欄還利用陰影顯示高度,表示它與內容處于不同的層級。
在 Icon 類中,SemanticLabel 字段是在 Flutter 中添加輔助功能信息的常用方法。這很像 Android 的 Content Label 或 iOS 的 UIAccessibility accessibilityLabel。你會在很多類中見到它。
這個字段的信息很好地向使用屏幕閱讀器的人說明了該按鈕的作用。
對于沒有 semanticLabel: 字段的部件,你可以將其包裝在 Semantics 部件中,在其 Flutter 文檔中了解更多有關的信息。
5. 在網格中添加卡片
現在我們的應用像點樣子了,讓我們接著放置一些卡片來組織內容。
卡片 是顯示單體內容和動作的獨立的元素。它們是一種可以靈活地呈現近似內容集合的方式。
在 Material 指南有關卡片的文章中了解更多信息。
要了解卡片部件,請參閱在 Flutter 中構建布局。
添加網格視圖
讓我們從應用欄底部添加一個卡片開始。單一的 卡片 部件不足以讓我們將它放到我們想要的位置,所以我們需要將它封裝在一個 網格視圖 中。
用 GridView 替換 Scaffold 中 body 字段的 Center:
// TODO: 添加網格視圖(102) body: GridView.count(crossAxisCount: 2,padding: EdgeInsets.all(16.0),childAspectRatio: 8.0 / 9.0,// TODO: 構建一組卡片(102)children: <Widget>[Card()], ), 復制代碼讓我們分析這段代碼。網格視圖調用 count() 構造函數,因要添加的項目數是可數的而不是無限的。但它需要更多信息來定義其布局。
crossAxisCount: 指定橫向顯示數目,我們設置成 2 列。
Flutter 中的 Cross axis(橫軸) 表示非滾動軸。可滾動的方向稱為 主軸。所以如果你的應用像網格視圖默認的那樣垂直滾動,那么橫軸就是水平方向。
詳情請參閱構建布局。
padding: 字段為網格視圖的 4 條邊設置填充。當然你現在看不到首尾的填充,因為網格視圖內還沒有其他子項。
childAspectRatio: 字段依據寬高比確定其大小。
默認地,網格視圖中的項目尺寸相同。
將這些加在一起,網格視圖按照如下方式計算每個子項的寬度:([整個網格寬度] - [左填充] - [右填充]) / 列數。在這里就是:([整個網格寬度] - 16 - 16) / 2。
高度是根據寬度計算得來的,通過應用寬高比:([整個網格寬度] - 16 - 16) / 2 * 9 / 8。我們翻轉了 8 和 9,因為我們是用寬度來計算高度。
我們已經有了一個空的卡片了,讓我們添加一些子部件到卡片中。
布局內容
卡片內應該包含一張圖片、一個標題和一個次級文本。
更新網格視圖的子項:
// TODO: 構建一組卡片(102) children: <Widget>[Card(child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[AspectRatio(aspectRatio: 18.0 / 11.0,child: Image.asset('assets/diamond.png'),),Padding(padding: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[Text('Title'),SizedBox(height: 8.0),Text('Secondary Text'),],),),],),) ], 復制代碼這段代碼添加了一個列部件,用來垂直地布局子部件。
crossAxisAlignment: 字段指定 CrossAxisAlignment.start 屬性,這意味著“文本與前沿對齊”。
AspectRatio 部件決定圖像的形狀,無論提供的是何種圖像。
Padding 使得文本與邊框保持一定距離。
兩個 Text 部件垂直堆疊,在其間保持 8 個單位的間隔(SizedBox)。我們使用另一個 Column 來把它們放到 Padding 中。
保存你的項目:
在這個預覽里,你可以看到卡片從邊緣置入,并帶有圓角和陰影(這代表著卡片的高度)。整個形狀在 Material 中被稱為 “container(容器)”。(不要與名為 Container 的實際部件類混淆。)
除了容器以外,在 Material 中卡片內所有的元素實際上都是可選的。你可以添加標題文本、縮略圖、頭像或者小標題文本、分隔符甚至是按鈕和圖標。
了解更多消息,請參閱 Material 指南上有關卡片的文章。
卡片經常以集合的形式和其他卡片一起出現,讓我們在網格視圖中給它們布局。
6. 生成卡片集合
每當屏幕上出現多張卡片時,它們就會組成一個或多個集合。集合中的卡片是共面的,這意味著卡片共享相同的靜止高度。(除了卡片被拾起或拖動,但在這里我們不會這么做。)
將卡片添加到集合
現在我們的卡片是網格視圖內的 children: 字段子項。這有一大段難以閱讀的嵌套代碼。讓我們將它提取到一個函數中來生成任意數量的空卡片,然后返回給我們。
// TODO: 生成卡片集合(102) List<Card> _buildGridCards(int count) {List<Card> cards = List.generate(count,(int index) => Card(child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[AspectRatio(aspectRatio: 18.0 / 11.0,child: Image.asset('assets/diamond.png'),),Padding(padding: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[Text('Title'),SizedBox(height: 8.0),Text('Secondary Text'),],),),],),),);return cards; } 復制代碼將生成的卡片分配給網格視圖的 children 字段。記得用新代碼替換網格視圖中的所有內容。
// TODO: 添加網格視圖(102) body: GridView.count(crossAxisCount: 2,padding: EdgeInsets.all(16.0),childAspectRatio: 8.0 / 9.0,children: _buildGridCards(10) // 替換所有內容 ), 復制代碼保存你的項目:
卡片已經在這了,但它們什么都沒有顯示。現在是時候添加一些產品數據了。
###添加產品數據
這個應用中的產品有著圖像、名稱和價格。讓我們把這些添加到已有的卡片部件中。
然后,在 home.dart 中,導入數據模型需要的新包和文件:
import 'package:flutter/material.dart'; import 'package:intl/intl.dart';import 'model/products_repository.dart'; import 'model/product.dart'; 復制代碼最后,更改 _buildGridCards() 來獲取產品信息,并將數據應用到卡片中:
// TODO: 生成卡片集合(102)// 替換整個方法 List<Card> _buildGridCards(BuildContext context) {List<Product> products = ProductsRepository.loadProducts(Category.all);if (products == null || products.isEmpty) {return const <Card>[];}final ThemeData theme = Theme.of(context);final NumberFormat formatter = NumberFormat.simpleCurrency(locale: Localizations.localeOf(context).toString());return products.map((product) {return Card(// TODO: 調整卡片高度(103)child: Column(// TODO: 卡片的內容設置居中(103)crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[AspectRatio(aspectRatio: 18 / 11,child: Image.asset(product.assetName,package: product.assetPackage,// TODO: 調整盒子尺寸(102)),),Expanded(child: Padding(padding: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),child: Column(// TODO: 標簽底部對齊并居中(103)crossAxisAlignment: CrossAxisAlignment.start,// TODO: 更改最內部的列(103)children: <Widget>[// TODO: 處理溢出的標簽(103)Text(product.name,style: theme.textTheme.title,maxLines: 1,),SizedBox(height: 8.0),Text(formatter.format(product.price),style: theme.textTheme.body2,),],),),),],),);}).toList(); } 復制代碼注意:應用現在無法編譯和運行,我們還需要進行修改。
要設置文本的樣式,我們使用當前 BuildContext 中的 ThemeData。
了解有關文本樣式的更多信息,請參閱 Material 指南中的排版一文。了解有關主題的更多信息,請參考教程下一章 MDC-103: Material Design Theming 的顏色、形狀、高度和類型。
在嘗試編譯之前,將 BuildContext 傳入 build() 方法中的 _buildGridCards():
// TODO: Add a grid view (102) body: GridView.count(crossAxisCount: 2,padding: EdgeInsets.all(16.0),childAspectRatio: 8.0 / 9.0,children: _buildGridCards(context) // Changed code ), 復制代碼你可能注意到了我們沒有在卡片間添加任何垂直的間隔,這是因為在其頂部與底部默認有 4 個單位的填充。
保存你的項目:
產品的數據顯示出來了,但是圖像四周有額外的空間。圖像默認依據 .scaleDown 的 BoxFit 繪制(在這個情況下)。讓我們將其更改為 .fitWidth 來讓它們放大一點,刪除多余的空間。
修改圖像的 fit: 字段:
// TODO: 調整盒子尺寸(102)fit: BoxFit.fitWidth, 復制代碼現在我們的產品完美的展現在應用中了!
7. 總結
我們的應用已經有了基本的流程,將用戶從登陸屏幕帶到可以查看產品的主屏幕。通過幾行代碼,我們添加了一個頂部應用欄(帶有標題和三個按鈕)以及卡片(用于顯示我們應用的內容)。我們的主屏幕簡潔實用,具有基本的結構和可操作的內容。
完成的 MDC-102 應用可以在 103-starter_and_102-complete 分支中找到。
你可以用此分支下的應用來對照驗證你的版本。
下一步
通過頂部應用欄、卡片、文本框和按鈕,我們已經使用了 MDC-Flutter 庫中的四個核心組件!你可以訪問 Flutter 部件目錄來探索更多組件。
雖然它完全正常運行,我們的應用尚未表達任何特殊的品牌特點。在 MDC-103: Material Design Theming 的顏色、形狀、高度和類型中,我們將定制這些組件的樣式,來詮釋一個充滿活力的、現代的品牌。
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改并 PR,也可獲得相應獎勵積分。文章開頭的 本文永久鏈接 即為本文在 GitHub 上的 MarkDown 鏈接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、后端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。
總結
以上是生活随笔為你收集整理的[译] MDC-102 Flutter:Material 结构和布局(Flutter)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信新的用户信息接口wx.getUser
- 下一篇: nyoj-20-吝啬的国度(深搜)