本系列可能會伴隨大家很長時間,這裡我會從0開始搭建一個「網易雲音樂」的APP出來。
下面是該APP 功能的思維導圖:
因為工作的原因,一星期有可能只更新一篇該系列的文章,不過一星期最少一篇。
本章節為第一節,從建立專案說起。
建立「網易雲音樂」專案
首先看一下本地 Flutter 環境:
建立命令就都知道了,不用命令的話,用 AS 或者 VS 更簡單。
專案建立好後,刪除無用程式碼,然後開始建立資料夾:
一共分為六個資料夾:
- model:存放所有資料類
- pages:存放所有的頁面
- provider:存放所有的 Provider
- route:存放路由相關
- utils:存放所有的工具類
- widgets:存放所有封裝好的元件
下面我們開始新增依賴。
新增外掛
首先對我們一些大概的功能有一個瞭解,
例如 網路請求肯定有,那我會選擇 Dio 來當做網路請求的外掛,
下面是目前所想到的外掛:
外掛 | 作用 |
---|---|
Provider | 狀態管理,UI、資料 分離 |
shared_preferences | 本地儲存資料,持久化 |
dio | 網路請求 |
flutter_screenutil | 螢幕適配 |
fluro | 路由管理 |
common_utils | Dart 常用工具類 |
dio_cookie_manager | dio cookie 工具 |
cookie_jar | Cookie 管理 |
permission_handler | 許可權處理 |
path_provider | 沙盒路徑 |
extended_image | 屌炸天的 Image 擴充套件 |
通用程式碼
功能如下:
外掛 | 作用 |
---|---|
routes.dart | fluro 的路由管理 |
net_utils.dart | 網路請求管理 |
common_text_style.dart | 一些通用的 text 樣式 |
h_empty_view.dart | 橫向空元件(用於佔位) |
v_empty_view.dart | 縱向空元件(用於佔位) |
loading.dart | 載入元件 |
widget_future_builder.dart | 網路請求元件 |
widget_net_error.dart | 網路請求失敗元件 |
其中 widget_future_builder.dart
在我上一篇文章:Flutter | 定義一個通用的多功能網路請求 Widget 中已經說過了,這裡就不多說了。
挑幾個沒說過的說一下。
loading.dart
用於顯示載入中的元件。
開始的時候考慮用 showDialog
來做,但是它預設會把背景變成半透明的黑色。
然後檢視原始碼,發現他是呼叫 showGeneralDialog
來建立的對話方塊,傳入了一個 barrierColor: Colors.black54
來控制的半透明背景。
那我可以自己來使用 showGeneralDialog
,關於該控制元件的介紹及使用,我這裡就不多贅述了,可以檢視caijinglong的部落格 - Flutter dialog (2) - showGeneralDialog的使用。
最後我這裡的程式碼就是這樣(擷取一部分):
class Loading {
static bool isLoading = false;
static void showLoading(BuildContext context) {
if (!isLoading) {
isLoading = true;
showGeneralDialog(
context: context,
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
return xxx;
}).then((v) {
// 消失的時候把狀態置為 false
isLoading = false;
});
}
}
static void hideLoading(BuildContext context) {
if (isLoading) {
Navigator.of(context).pop();
}
}
}
複製程式碼
只提供了兩個靜態方法:showLoading()
、hideLoading()
。
showLoading
邏輯如下:
- 首先判斷
isLoading
是否為 true,如果正在顯示 loading,那麼則不作操作 - 如果不為 true,則顯示 loading,並把狀態置為 true
- 呼叫
then
方法,在 dialog 消失的時候把狀態置為 false
net_utils.dart
網路請求的管理&工具類。
在這個檔案中,我們要進行 Dio 的初始化和網路請求的封裝。
在檢視 API 文件的時候,發現登入狀態是由 Cookie 來管理的。 所以我要使用 cookie 的外掛來滿足需求。
寫一個初始化的方法,在 runApp 時呼叫:
static Dio _dio;
static void init() async {
// 獲取沙盒路徑,用於儲存 cookie
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
CookieJar cj = PersistCookieJar(dir: tempPath);
_dio = Dio(BaseOptions(baseUrl: 'http://127.0.0.1:3000'))
..interceptors.add(CookieManager(cj))
..interceptors.add(LogInterceptor(responseBody: true, requestBody: true));
}
複製程式碼
然後再寫一個通用的 _get()
方法,所有的網路請求最終都經過它:
static Future<Response> _get(BuildContext context, String url,
{Map<String, dynamic> params}) async {
Loading.showLoading(context);
try {
return await _dio.get(url, queryParameters: params);
} on DioError catch (e) {
if (e.response is Map) {
return Future.value(e.response);
} else {
return Future.error(0);
}
} finally {
Loading.hideLoading(context);
}
}
複製程式碼
這個邏輯我在上一篇文章中也提到過,如果返回狀態不是 2xx,那就會丟擲 DioError
,然後我們在這裡處理邏輯即可。
common_text_style.dart
一些通用的 text 樣式。
我們在這裡建立一些 頂級變數 :
final commonTextStyle = TextStyle(fontSize: 16, color: Colors.black87);
final smallCommonTextStyle = TextStyle(fontSize: 12, color: Colors.black87);
final smallGrayTextStyle = TextStyle(fontSize: 12, color: Colors.grey);
複製程式碼
這樣其他類使用起來就很方便,萬一以後要改文字樣式也很方便。
總結
該篇文章是當前系列的第一篇,主要提供了一些搭建專案的思路。
該系列文章程式碼會傳至 GitHub:github.com/wanglu1209/…
並且每次提交都會對應一個分支。
本文中的程式碼請在 NeteaseCloudMusic-Day1 分支中檢視程式碼。
另我個人建立了一個「Flutter 交流群」,可以新增我個人微信 「17610912320」來入群。