版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2019.11.03 星期日 |
前言
Flutter是谷歌的移動UI框架,可以快速在iOS和Android上構建高質量的原生用戶界面。 Flutter可以與現有的代碼一起工作。在全世界,Flutter正在被越來越多的開發者和組織使用,并且Flutter是完全免費、開源的。目前公司的部分模塊就是在使用Flutter進行開發。感興趣的可以看下面幾篇文章。
1. Flutter開發技術與分享(一) —— 基本概覽(一)
開始
首先看下主要內容
通過使用
VS Code
編寫跨平臺應用程序,深入研究Flutter
框架,以在單個代碼庫中構建iOS
和Android
應用程序。下面是翻譯文章的地址。
然后看下寫作環境
寫作環境:Dart 2, Flutter 1.7, VS Code
自十年前iOS
和Android
平臺風起云涌以來,跨平臺開發一直是整個移動開發領域的目標。 能夠為iOS和Android編寫一個應用程序的功能可以為您的公司和團隊節省大量時間和精力。
多年來,已經發布了用于跨平臺開發的各種工具,包括基于Web的工具(例如Adobe
的PhoneGap),強大的框架(例如Microsoft
的Xamarin)以及更新的工具(例如Facebook
的React Native)。 每個工具集都有其優缺點,并且在移動行業中獲得了不同程度的成功。
進入跨平臺領域的最新框架是Google
的Flutter。 Flutter在兩個平臺上均具有快速的開發周期,快速的UI呈現,獨特的UI設計以及本機應用程序性能。
Introduction to Flutter
Flutter
應用程序是使用Dart編程語言編寫的,該語言最初也來自Google
,現在是ECMA
標準。 Dart
與其他現代語言(例如Kotlin
和Swift
)具有許多相同的功能,并且可以轉編譯為JavaScript
代碼。
作為跨平臺框架,Flutter
最類似于React Native
,因為Flutter
允許響應式和聲明式編程風格。但是,與React Native
不同,Flutter
不需要使用Javascript
橋接,這可以縮短應用程序的啟動時間和整體性能。 Dart
通過使用Ahead-Of-Time
或AOT
編譯來實現此目的。
Dart
的另一個獨特之處在于它還可以使用Just-In-Time or JIT
編譯。 Flutter
的JIT
編譯通過允許熱重裝(hot reload)
功能在開發過程中刷新UI而無需全新的構建,從而改善了開發工作流程。
正如您將在本教程中看到的那樣,Flutter
框架主要圍繞widgets
的概念構建。在Flutter中,widgets
不僅用于應用程序的視圖,而且還用于整個屏幕甚至應用程序本身。
除了跨平臺的iOS和Android開發之外,學習Flutter還可以讓您搶先開發Fuchsia平臺,Fuchsia
平臺目前是Google
開發的實驗性操作系統。
在本教程中,您將構建一個Flutter
應用程序,該應用程序將查詢GitHub API中的GitHub組織中的團隊成員,并在可滾動列表中顯示團隊成員信息:
您可以同時使用iOS
模擬器或Android
模擬器來開發應用程序!
在構建應用程序時,您將了解有關Flutter的以下知識:
Setting up your development environment
Creating a new project
Hot reload
Importing files and packages
Using widgets and creating your own
Making network calls
Showing items in a list
Adding an app theme
順帶著你也會學習一點關于Dart
的知識。
Setting up your development environment
Flutter
開發可以在macOS
,Linux
或Windows
上完成。 盡管您可以將任何編輯器與Flutter工具鏈一起使用,但是有 IntelliJ IDEA,Android Studio和Visual Studio Code的IDE
插件可以簡化開發周期。 在本教程中,我們將使用VS Code
。
在此處here可以找到有關使用Flutter框架設置開發機器的說明?;静襟E因平臺而異,但大多數情況是:
- 1) 下載適用于您開發計算機操作系統的安裝包,以獲取
Flutter SDK
的最新穩定版本 - 2) 將安裝包解壓縮到所需位置
- 3) 將flutter工具添加到您的路徑
- 4) 運行
flutter doctor
命令,該命令將安裝Flutter框架(包括Dart
)并提醒您任何缺少的依賴項 - 5) 安裝缺少的依賴項
- 6) 使用Flutter插件/擴展程序設置您的IDE
- 7) 測試驅動一個應用
Flutter網站上提供的說明做得很好,可以讓您輕松地在所選平臺上設置開發環境。本教程的其余部分假定您已經為Flutter開發設置了VS Code
,并且已經解決了flutter doctor
發現的所有問題。
如果您使用的是Android Studio
,那么您也應該能夠很好地遵循。您還需要運行iOS模擬器,Android模擬器,或者已設置預配置的iOS設備或Android設備進行開發。
注意:要在iOS模擬器或iOS設備上進行構建和測試,您需要使用已安裝Xcode的
macOS
。
Creating a new project
在安裝了Flutter擴展的VS Code
中,通過選擇View ? Command Palette…
或在macOS上單擊Cmd-Shift-P
或在Linux或Windows上單擊Ctrl-Shift-P
來打開命令面板。 在面板中輸入Flutter:New Project
,然后按回車鍵。
輸入項目的名稱ghflutter
,然后按回車鍵。 選擇一個文件夾來存儲項目,然后等待Flutter在VS Code
中設置項目。 項目準備就緒后,將在編輯器中打開文件main.dart
。
在VS Code
中,您會在左側看到一個面板,該面板顯示您的項目結構。 有適用于iOS和Android的文件夾,還有一個包含main.dart
的lib
文件夾,并且具有適用于兩個平臺的代碼。 僅在本教程中,您將在lib
文件夾中工作。
用以下內容替換main.dart
中的代碼:
import 'package:flutter/material.dart';
void main() => runApp(GHFlutterApp());
class GHFlutterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'GHFlutter',
home: Scaffold(
appBar: AppBar(
title: Text('GHFlutter'),
),
body: Center(
child: Text('GHFlutter'),
),
),
);
}
}
頂部附近的main()
函數對單個行函數使用=>
運算符來運行該應用程序。 您有一個名為GHFlutterApp
的應用程序類。
您在這里看到您的應用程序本身是一個StatelessWidget
。 Flutter應用程序中的大多數實體都是無狀態或有狀態的widgets
。 您可以覆蓋widgets
的build()
方法來創建應用widgets
。 您正在使用MaterialApp
widgets
,該widgets
提供了Material Design
之后的應用所需的許多組件。
對于本入門教程,通過右鍵單擊,選擇Delete
選項,然后確認刪除,從項目中刪除test
文件夾中的測試文件widget_test.dart
。
如果您使用的是macOS
,請啟動iOS模擬器。 您也可以在macOS,Linux或Windows上使用Android模擬器。 如果iOS模擬器和Android模擬器都在運行,則可以使用VS Code
窗口右下方的菜單在它們之間進行切換:
要構建和運行項目,您需要首先設置啟動配置。
通過單擊左側面板上的crossed bug
圖標,切換到Debug View
。
您會注意到,到目前為止,尚未定義任何配置。 單擊No Configuration
以獲取下拉列表并選擇Add Configuration
VS Code
將創建一個launch.json
文件,其詳細信息如下:
注意:選擇
Add Configuration
項后,將自動為您生成此文件。 在本教程中,您無需修改它。
現在,您已經完成所有工作,可以通過按F5
或選擇Debug ? Start Debugging
或單擊綠色的播放圖標來構建和運行項目。 您會看到Debug Console
已打開,并且如果在iOS上運行,則會看到用于構建項目的Xcode。 如果在Android上運行,則會看到Gradle
被調用以進行構建。
這是在iOS模擬器中運行的應用程序:
下面,在Android模擬器中運行:
您看到的慢速模式banner
表明該應用程序正在調試模式下運行。
您可以通過單擊VS Code
窗口頂部工具欄右側的停止按鈕來停止正在運行的應用程序:
通過單擊VS Code
左上方的圖標或選擇View ? Explorer
,可以返回項目視圖。
Hot Reload
Flutter
開發的最佳方面之一是能夠在進行更改時熱重新加載您的應用程序。 這類似于Android Studio
的Instant Run/Apply Changes
。
構建并運行該應用程序,使其在模擬器或模擬器上運行:
現在,無需停止正在運行的應用程序,請將應用程序欄字符串更改為其他內容:
appBar: AppBar(
title: Text('GHFlutter App'),
),
現在,單擊工具欄上的熱重載按鈕或直接保存main.dart
文件:
一兩秒鐘之內,您應該會看到正在運行的應用程序中反映出的更改:
熱重載功能可能并不總是有效,官方文檔official docs可以很好地解釋無法使用的情況,但總體而言,在構建UI時可節省大量時間。
Importing a File
您將希望能夠從創建的其他類中導入代碼,而不是將所有Dart代碼都保存在單個main.dart
文件中。 現在,您將看到一個導入字符串的示例,該示例在需要本地化面向用戶的字符串時會有所幫助。
右鍵單擊lib
并選擇New File
,在lib
文件夾中創建一個名為strings.dart
的文件:
將以下類添加到新文件中:
class Strings {
static String appTitle = "GHFlutter";
}
將以下import
添加到main.dart
的頂部
import 'strings.dart';
更改widget
以使用新的字符串類,以便GHFlutterApp
類如下所示:
class GHFlutterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: Strings.appTitle,
home: Scaffold(
appBar: AppBar(
title: Text(Strings.appTitle),
),
body: Center(
child: Text(Strings.appTitle),
),
),
);
}
}
按下F5
鍵即可構建并運行該應用,您應該不會有任何變化,但是現在您正在使用字符串文件中的字符串。
Widgets
Flutter
應用程序中的幾乎每個元素都是widget
。 widget
被設計為不可變的,因為使用不可變的widget
有助于使應用程序UI保持輕便。
您將使用兩種基本類型的小部件:
-
Stateless - 無狀態:僅依賴于自己的配置信息的
widget
,例如圖像視圖中的靜態圖像。 -
Stateful - 有狀態:需要維護動態信息并通過與
State
對象進行交互來實現的信息。
無狀態小部件和有狀態widget
都在Flutter
應用程序中的每幀上重新繪制,不同之處在于,有狀態widget
將其配置委托給State
對象。
要開始制作自己的widget
,請在main.dart
底部創建一個新類:
class GHFlutter extends StatefulWidget {
@override
createState() => GHFlutterState();
}
您已經創建了StatefulWidget
子類,并且您將覆蓋createState()
方法以創建其狀態對象。 現在,在GHFlutter
上方添加GHFlutterState
類:
class GHFlutterState extends State<GHFlutter> {
}
GHFlutterState
使用GHFlutter
的參數擴展State
。
制作widget
時的主要任務是覆蓋將widget
呈現到屏幕時調用的build()
方法。
在GHFlutterState
中添加一個build()
重寫:
@override
Widget build(BuildContext context) {
?
}
填寫build()
如下:
@override
Widget build(BuildContext context) {
return Scaffold (
appBar: AppBar(
title: Text(Strings.appTitle),
),
body: Text(Strings.appTitle),
);
}
Scaffold
是用于材料設計widgets
的容器。 它充當widgets
層次結構的根。 您已在Scaffold
中添加了一個AppBar
和一個body
,每個都包含一個Text widget
。
更新GHFlutterApp
,使其使用新的GHFlutter
小部件作為其home
屬性,而不是構建自己的支架:
class GHFlutterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: Strings.appTitle,
home: GHFlutter(),
);
}
}
構建并運行該應用程序,您將看到新的widget
在起作用:
尚未發生太大變化,但是現在您可以設置以構建新的widget
。
Making Network Calls
之前,您已將strings.dart
文件導入到項目中。 您可以類似地導入Flutter
框架和Dart
中包含的其他軟件包。
例如,您現在將使用框架中可用的包進行HTTP
網絡調用,并將生成的響應JSON
解析為Dart
對象。 在main.dart
頂部添加兩個新導入:
import 'dart:convert';
import 'package:http/http.dart' as http;
您會注意到http
包不可用。 這是因為尚未將其添加到項目中。 導航到pubspec.yaml
文件,然后在dependencies
和cupertino_icons:^ 0.1.2
下添加以下內容:
cupertino_icons: ^0.1.2
# HTTP package
http: ^0.12.0+2
注意:注意縮進。 保持 http 軟件包聲明的縮進與
cupertino_icons
軟件包的縮進相同。
現在,當您保存pubspec.yaml
文件時,VS Code
中的Flutter
擴展名將運行flutter pub get
命令。 Flutter將獲得聲明的http
軟件包,您的軟件包也將在main.dart
中可用。
現在,您將在main.dart
中看到有關當前未使用的導入的指示器。
Dart
應用程序是單線程的,但是Dart提供了對在其他線程上運行代碼以及運行異步代碼的支持,這些異步代碼不會使用async / await
模式阻止UI線程。
您將進行異步網絡調用以檢索GitHub
團隊成員的列表。 在GHFlutterState
的頂部添加一個空列表作為屬性,還添加一個屬性以容納文本樣式:
var _members = [];
final _biggerFont = const TextStyle(fontSize: 18.0);
名稱開頭的下劃線使該類的成員成為私有成員。
要進行異步HTTP
調用,請向GHFlutterState
添加方法_loadData()
:
_loadData() async {
String dataURL = "https://api.github.com/orgs/raywenderlich/members";
http.Response response = await http.get(dataURL);
setState(() {
_members = json.decode(response.body);
});
}
您已經在_loadData()
上添加了async
關鍵字,以告知Dart
它是異步的,并且還在http.get()
調用上阻塞了await
關鍵字。 您使用的dataUrl
值設置為GitHub API
端點,該端點檢索GitHub
組織的成員。
HTTP調用完成后,您將向回調傳遞給setState()
,該回調在UI線程上同步運行。 在這種情況下,您將解碼JSON響應并將其分配給_members
列表。
將initState()
重寫添加到GHFlutterState
,該狀態在初始化狀態時調用_loadData()
:
@override
void initState() {
super.initState();
_loadData();
}
Using a ListView
現在您已經有了Dart
成員列表,您需要一種在UI列表中顯示它們的方法。 Dart
提供了一個ListView
widget
,可讓您在列表中顯示數據。 ListView
的行為類似于Android
上的RecyclerView
和iOS上的UITableView
,在用戶滾動列表以實現平滑滾動性能時回收視圖。
將_buildRow()
方法添加到GHFlutterState
中:
Widget _buildRow(int i) {
return ListTile(
title: Text("${_members[i]["login"]}", style: _biggerFont)
);
}
您將返回一個ListTile widget
,該widget
顯示從ith
成員的JSON解析的login
值,并使用您之前創建的文本樣式。
更新GHFlutterState
的構建方法,使其主體為ListView.builder
:
body: ListView.builder(
padding: const EdgeInsets.all(16.0),
itemCount: _members.length,
itemBuilder: (BuildContext context, int position) {
return _buildRow(position);
}),
你已經添加padding
,itemCount
設置為成員的數量,并使用_buildRow()
為給定的位置設置itemBuilder
。
您可以嘗試熱重載,但可能會收到“Full restart may be required”
消息。 如果是這樣,請按F5鍵構建并運行該應用程序:
進行網絡通話,解析數據并在列表中顯示結果就是這么簡單!
Adding dividers
要將分隔符添加到列表中,您需要將item
數量加倍,然后在列表中的位置為奇數時返回Divider widget
。 如下更新GHFlutterState
的構建方法:
body: ListView.builder(
itemCount: _members.length * 2,
itemBuilder: (BuildContext context, int position) {
if (position.isOdd) return Divider();
final index = position ~/ 2;
return _buildRow(index);
}),
確保不要錯過itemCount
上的* 2
。 有了分隔線后,您已經從構建器中刪除了padding
。 在itemBuilder
中,您要么返回Divider()
,要么通過整數除法并使用_buildRow()
來構建行項目來計算新索引。
嘗試熱重載,您應該在列表上看到分隔線:
要將padding
重新添加到每一行中,您想在_buildRow()
中使用Padding widget
:
Widget _buildRow(int i) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: ListTile(
title: Text("${_members[i]["login"]}", style: _biggerFont)
)
);
}
ListTile
現在是padding widget
的子widget
。 熱重新加載以查看行上的padding
,而不是分隔線上的padding
。
Parsing to Custom Types
在上一節中,JSON解析器將JSON響應中的每個成員作為Dart Map
類型添加到_members
列表中,相當于Kotlin
中的Map
或Swift
中的Dictionary
。
但是,您還希望能夠使用自定義類型。
在main.dart
文件中添加一個新的Member
類型:
class Member {
final String login;
Member(this.login) {
if (login == null) {
throw ArgumentError("login of Member cannot be null. "
"Received: '$login'");
}
}
}
成員具有login
屬性和一個構造函數,如果登錄值為null
,則該構造函數將拋出錯誤。
更新GHFlutterState
中的_members
聲明,以便它是Member
對象的列表:
var _members = <Member>[];
更新_buildRow()
以在Member
對象上使用login
屬性,而不是使用映射上的login
鍵:
title: Text("${_members[i].login}", style: _biggerFont)
現在,更新發送到_loadData()
中的setState()
的回調,以將解碼后的映射轉換為Member
對象并將其添加到成員列表中:
setState(() {
final membersJSON = json.decode(response.body);
for (var memberJSON in membersJSON) {
final member = Member(memberJSON["login"]);
_members.add(member);
}
});
如果嘗試進行熱重裝,您可能會看到一個錯誤,但是停止并按F5鍵來構建和運行該應用,您應該會看到與以前相同的屏幕,除了現在使用新的Member
類。
Downloading Images with NetworkImage
來自GitHub
的每個成員都有其頭像的URL。 現在,您將該頭像添加到Member
類中,并在應用程序中顯示頭像。
更新Member
類以添加一個avatarUrl
屬性,該屬性不能為null
:
class Member {
final String login;
final String avatarUrl;
Member(this.login, this.avatarUrl) {
if (login == null) {
throw ArgumentError("login of Member cannot be null. "
"Received: '$login'");
}
if (avatarUrl == null) {
throw ArgumentError("avatarUrl of Member cannot be null. "
"Received: '$avatarUrl'");
}
}
}
使用NetworkImage
和CircleAvatar
widget
更新_buildRow()
以顯示頭像:
Widget _buildRow(int i) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: ListTile(
title: Text("${_members[i].login}", style: _biggerFont),
leading: CircleAvatar(
backgroundColor: Colors.green,
backgroundImage: NetworkImage(_members[i].avatarUrl)
),
)
);
}
通過將頭像設置為ListTile
的leading
屬性,它將在行內標題之前顯示。 您還使用Colors
類在圖片上設置了背景色。
現在更新_loadData()
以在創建新Member
時使用映射中的“ avatar_url”
值:
final member = Member(memberJSON["login"], memberJSON["avatar_url"]);
使用F5停止,構建和運行該應用程序。 您會在每一行中看到您的成員頭像:
Cleaning the Code
現在,您的大多數代碼都位于main.dart
文件中。 為了使代碼更簡潔,您可以重構已添加到文件中的widget
和其他類。
在lib
文件夾中創建名為member.dart
和ghflutter.dart
的文件。 將Member
類移至member.dart
,并將GHFlutterState
和GHFlutter
類移至ghflutter.dart
。
您在member.dart
中不需要任何import
語句,但是ghflutter.dart
中的導入應如下所示:
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'member.dart';
import 'strings.dart';
您還需要更新main.dart
中的導入,以便整個文件包含以下內容:
import 'package:flutter/material.dart';
import 'ghflutter.dart';
import 'strings.dart';
void main() => runApp(GHFlutterApp());
class GHFlutterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: Strings.appTitle,
home: GHFlutter(),
);
}
}
按下F5來構建和運行該應用程序,您應該看不到任何更改,但是代碼現在更簡潔了。
Adding a Theme
您可以通過將theme
屬性添加到您在main.dart
中創建的MaterialApp
中,輕松地將主題添加到應用中:
class GHFlutterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: Strings.appTitle,
theme: ThemeData(primaryColor: Colors.green.shade800),
home: GHFlutter(),
);
}
}
您將綠色用作主題的“材料設計”顏色值。
按下F5來構建和運行應用程序,以查看新的主題:
大多數應用程序屏幕截圖均來自Android模擬器。 您還可以在iOS模擬器中運行最終的主題應用程序:
這就是我所說的跨平臺!
有關Flutter
和Dart
的知識還有很多。 最好的起點是:
-
flutter.dev上的
Flutter
主頁。 您會發現很多很棒的文檔和其他信息。 - 在此處here查看可用的
widgets
。 - 這里here有一個很好的指南供
Android
開發人員過渡到使用Flutter
。 - 適用于
React Native
開發人員的類似指南在這里here。
后記
本篇主要講述了Flutter 入門,感興趣的給個贊或者關注~~~