flutter项目重构,趁此机会整理一下所用到的知识
应用的初步构建
Android名称和图标修改
在/android/app/src/main/AndroidManifest.xml
中修改相应配置
<application
android:name="io.flutter.app.FlutterApplication"
android:label="cloudrecord"
android:icon="@mipmap/ic_launcher">
label为应用名称,icon为图标。@mipmap代表/android/app/src/main/res/
中的mipmap文件夹,图像需要png格式。
iOS名称和图标修改
在/ios/Runner/info.plist
中修改名称
<key>CFBundlePackageType</key>
<string>APPL</string>
在\ios\Runner\Assets.xcassets\AppIcon.appiconset
文件夹中修改图标,在\ios\Runner\Assets.xcassets\AppIcon.appiconset\Contents.json
中修改对应关系
##修改应用版本号
在pubspec.yaml
中可看到版本号为version: 1.0.0+1
在Android中,应用的版本分为versionCode
& versionName
versionCode
:内部管理的版本号
versionName
:用户显示的版本号
在iOS中,应用的版本分为 version
& build
version
:用户显示的版本
build
:内部管理的版本
Flutter中对应的版本号为
1.0.0
:用户显示的版本
1
:内部管理的版本
##用户权限配置
在/android/app/src/main/AndroidManifest.xml
中修改权限配置
加入以下两行
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
分别为存储空间以及网络请求
网络封装
获取Dio依赖
flutter自带网络请求库功能较弱且配置麻烦,因此使用dio库作为http请求的包
在pubspec.yaml
中的dependencies
下配置相应依赖包
这里我一次加入后面需要的大多数包,注意版本匹配
然后点击peckages get获取相应的包
为网络传输添加弹窗提示
在进行体积较大数据的传输时,如果没有提示,用户会感到迷惑,所以做一个半透明的loading窗口
使用dialog方法
import 'package:flutter/material.dart';
dialog方法详解
Future<T> showDialog<T>({
BuildContext context,
bool barrierDismissible,
Widget child,
Widget Function(BuildContext) builder,
bool useRootNavigator,
RouteSettings routeSettings
})
其中 context
和 builder
是必传项,builder 需要返回一个 Widget,这个 Widget 会被作为 dialog 展示在页面上
编写一个半透明窗口作为showDialog的widget
class NetLoadingDialog extends StatefulWidget {
String loadingText;
NetLoadingDialog(
{Key key,
this.loadingText = "loading...",
})
: super(key: key);
@override
State<NetLoadingDialog> createState() => _LoadingDialog();
}
class _LoadingDialog extends State<NetLoadingDialog> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return new GestureDetector(
// 点击退出当前页面
// onTap: (){Navigator.of(context).pop();},
child: Material(
type: MaterialType.transparency,
child: new Center(
child: new SizedBox(
width: 120.0,
height: 120.0,
child: new Container(
decoration: ShapeDecoration(
color: Color(0xffffffff),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
),
),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new CircularProgressIndicator(),
new Padding(
padding: EdgeInsets.only(
top: 20.0,
),
child: new Text(
widget.loadingText,
style: new TextStyle(fontSize: 12.0),
),
),
],
),
),
),
),
),
);
}
}
效果如下
窗口使用了覆盖屏幕的组件
//会在当前屏幕内容基础上再覆盖一个满屏的区域
Material(
type = MaterialType.transparency, //屏幕灰色透明,即相当于覆盖一个灰色透明的div
child:内容组件
)
动画使用了进度条组件,包含两种,圆形进度条CircularProgressIndicator
和条形进度条LinearProgressIndicator
new LinearProgressIndicator(
backgroundColor: Colors.blue,
value: 0.2, //如果 value 为 null 或空,则显示一个动画,否则显示一个定值。Progress 的值只能设置 0 ~ 1.0,如果大于 1,则表示已经结束。
valueColor: new AlwaysStoppedAnimation<Color>(Colors.red),
),
new CircularProgressIndicator(
strokeWidth: 4.0,
backgroundColor: Colors.blue,
value: 0.2,
valueColor: new AlwaysStoppedAnimation<Color>(Colors.red),
),
对Dio进行封装
参考博客https://www.jianshu.com/p/edb5bae85732
非常感谢!
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'showAlertDialogClass.dart';
import 'dart:async';
import 'package:dio/dio.dart';
import 'dart:convert';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'globalConfig.dart';
import 'resultCode.dart';
/*
* 网络请求管理类
*/
class DioManager {
//写一个单例
//在 Dart 里,带下划线开头的变量是私有变量
static DioManager _instance;
static DioManager getInstance() {
if (_instance == null) {
_instance = DioManager();
}
return _instance;
}
Dio dio = new Dio();
DioManager() {
// Set default configs
dio.options.headers = {
"version": '2.0.9',
};
dio.options.baseUrl = " ";
dio.options.connectTimeout = 5000;
dio.options.receiveTimeout = 3000;
dio.interceptors
.add(LogInterceptor(responseBody: GlobalConfig.isDebug)); //是否开启请求日志
dio.interceptors.add(CookieManager(CookieJar())); //缓存相关类
}
//get请求
get(String url, Map params, Function successCallBack,
Function errorCallBack) async {
_requstHttp(url, successCallBack, 'get', params, errorCallBack);
}
//post请求
post(String url, params, Function successCallBack,
Function errorCallBack) async {
_requstHttp(url, successCallBack, "post", params, errorCallBack);
}
_requstHttp(String url, Function successCallBack,
[String method, params, Function errorCallBack]) async {
Response response;
try {
if (method == 'get') {
if (params != null && params.length > 0) {
response = await dio.get(url, queryParameters: params);
} else {
response = await dio.get(url);
}
} else if (method == 'post') {
if (params != null && params.length > 0) {
response = await dio.post(url, data: params);
} else {
response = await dio.post(url);
}
}
} on DioError catch (error) {
// 请求错误处理
Response errorResponse;
if (error.response != null) {
errorResponse = error.response;
} else {
errorResponse = new Response(statusCode: 666);
}
// 请求超时
if (error.type == DioErrorType.CONNECT_TIMEOUT) {
errorResponse.statusCode = ResultCode.CONNECT_TIMEOUT;
}
// 一般服务器错误
else if (error.type == DioErrorType.RECEIVE_TIMEOUT) {
errorResponse.statusCode = ResultCode.RECEIVE_TIMEOUT;
}
// debug模式才打印
if (GlobalConfig.isDebug) {
print('请求异常: ' + error.toString());
print('请求异常url: ' + url);
print('请求头: ' + dio.options.headers.toString());
print('method: ' + dio.options.method);
}
_error(errorCallBack, error.message);
return '';
}
// debug模式打印相关数据
if (GlobalConfig.isDebug) {
print('请求url: ' + url);
print('请求头: ' + dio.options.headers.toString());
if (params != null) {
print('请求参数: ' + params.toString());
}
if (response != null) {
print('返回参数: ' + response.toString());
}
}
String dataStr = json.encode(response.data);
Map<String, dynamic> dataMap = json.decode(dataStr);
if (dataMap == null || dataMap['state'] == 0) {
_error(
errorCallBack,
'错误码:' +
dataMap['errorCode'].toString() +
',' +
response.data.toString());
} else if (successCallBack != null) {
successCallBack(dataMap);
}
}
_error(Function errorCallBack, String error) {
if (errorCallBack != null) {
errorCallBack(error);
}
}
}