本系列可能会伴随你们很长时间,这里我会从0开始搭建一个「网易云音乐」的APP出来。git
下面是该APP 功能的思惟导图:github
由于工做的缘由,一星期有可能只更新一篇该系列的文章,不过一星期最少一篇。微信
本章节为第一节,从建立项目提及。cookie
首先看一下本地 Flutter 环境:网络
建立命令就都知道了,不用命令的话,用 AS 或者 VS 更简单。async
项目建立好后,删除无用代码,而后开始建立文件夹:ide
一共分为六个文件夹:工具
下面咱们开始添加依赖。post
首先对咱们一些大概的功能有一个了解,ui
例如 网络请求确定有,那我会选择 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 中已经说过了,这里就很少说了。
挑几个没说过的说一下。
用于显示加载中的组件。
开始的时候考虑用 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,那么则不做操做then
方法,在 dialog 消失的时候把状态置为 false网络请求的管理&工具类。
在这个文件中,咱们要进行 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
,而后咱们在这里处理逻辑便可。
一些通用的 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」来入群。