最近时间比较多,就把项目中可能用到的知识用 flutter 大概写了一遍,因此就分享出来加强下印象。javascript
官方文档直接使用版本号的这个部分说错了,版本号不须要带引号的,因此正确的方式是在 pubspec.yaml
文件中的dependencies
的下方加入html
fluro: ^1.5.1
复制代码
以后编辑器便可根据 flutter 命令自行安装依赖,或者在项目根目录运行 flutter pub get
,具体流程见 flutter 官网前端
官方文档说的比较简略,我看了 flutter go 的代码之后,总结了这个路由库的使用方式以下:java
runApp
方法运行以前或者在 根类 MyApp 的构造函数 中,我选择了后者。router 实例最好是全局变量,这样在其余文件中也能访问。代码在这里MaterialApp
的 onGenerateRoute
改写为如下代码。在这里用到了 router,因此必定要在第 2 步中确保路由已经被正确初始化。onGenerateRoute: (settings) {
return Application.router.generator(settings);
}
复制代码
router.navigateTo(context, "/users/1234", transition: TransitionType.fadeIn);
,也可使用 flutter 提供的路由跳转方式,Navigator.of(context).pushNamed("/users/1234", arguments: {"from": "ui"})
。须要修改页面转场动画使用前者,须要携带额外的参数建议使用后者。由于转场动画能够在第 2 步中进行设置,而且前者只提供了动态参数的传递,若是须要传递 Map
数据还得编码解码,因此我更人更推荐后者。ios
webview_flutter: ^0.3.16
复制代码
代码在这里git
ios/Runner/Info.plist
的 dict
内添加 <key>io.flutter.embedded_views_preview</key> <string>YES</string>
WebView
了,使用方式相对于插件的方式要简单的多,在定义组件时能够提供方法供 js 使用,向 js 传值则须要控制器的 evaluateJavascript 方法。WebView(
// webview的url
initialUrl: url ?? 'https://www.baidu.com/',
// 监听页面url的变化,根据返回值决定跳转仍是阻止
navigationDelegate: (request) {
if (request.url.startsWith('https://www.youtube.com/')) {
print('blocking navigation to $request}');
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
// flutter向js注入全局变量,而后js就能够调用flutter的方法
// 例子中js的window会多出一个 Print 对象,js调用Print.postMessage('我是js')时,在flutter中则会打印 js传过来的值: 我是js
javascriptChannels: {
JavascriptChannel(
name: 'Print',
onMessageReceived: (JavascriptMessage msg) {
print('js传过来的值: ' + msg.message);
}
),
},
// 是否容许运行js
javascriptMode: JavascriptMode.unrestricted,
// webview 建立后肤将控制器赋值给实例变量,方便控制
onWebViewCreated: (webViewController) {
// _controller.complete(webViewController);
_webViewController = webViewController;
},
// 页面加载完成
onPageFinished: (String msg) {
// print('加载完成');
},
)
复制代码
WillPopScope
来监听页面的返回,从而进行更改。Future<bool> back() async {
bool canBack = await _webViewController?.canGoBack();
if (canBack) {
_webViewController.goBack();
} else {
Navigator.of(context).pop();
}
return false;
}
复制代码
evaluateJavascript
能够经过 flutter 执行 js,从而获得 js 返回的值或是向 js 中注入变量(好比用户信息等),但这是有限制的。在安卓,执行后返回的值是 JSON 格式化后的字符串。而在 iOS 中,只有基本类型的字符串,数组类型的字符串能够被返回,其余非基本类型则不被支持而且该Future 会以 error 形式返回。dio: ^3.0.1
复制代码
dio 的使用方式跟前端平时使用的 axios 区别不是很大,因此我在这里就只说一下我以前遇到的困难。github
Dio dio = new Dio();
dio.interceptors.add(DioCacheManager(CacheConfig(baseUrl: baseUrl)).interceptor);
复制代码
因此要封装某一个类 A 的时候,得新建一个类 B,而后在 B 的某一个方法中执行 A 的方法,进行操做后再进行返回。代码在这里web
在进行 http 请求时,根据参数来选择是否显示 loading 框。看了文档之后,发现 extra 参数在请求和响应中都存在,可是文档中并无提示 extra 是怎么传入的。后来看了类型提示,发现 extra 参数是包含在请求参数的 options 中的。其实,没有必要经过 extra 传递 loading 这个参数,能够直接在请求的地方进行封装。关于 loading 框的代码在这里json
处理响应数据,根据后端的错误码进行相应处理。原本想在 interceptors 中对响应数据进行处理的,可是若是这么处理以后,返回数据的类型提示就不正确了,因此最后仍是在拿到响应数据以后才进行处理的。redux
dependencies:
json_annotation: ^2.0.0
dev_dependencies:
json_model: ^0.0.2
build_runner: ^1.0.0
json_serializable: ^2.0.0
复制代码
flutter packages pub run json_model
dependencies:
dio_http_cache: ^0.2.0
复制代码
dio-http-cache 的 0.2.0 版本与 json_model 库依赖冲突,为解决依赖冲突依赖冲突
json_model的依赖目前是
json_annotation: ^2.2.0
json_serializable: ^2.0.0
为了兼容http_cache,须要升级这两个依赖包的版本
json_annotation: ^3.0.0
json_serializable: ^3.0.0
复制代码
dio-http-cache interceptor
dio.interceptors.add(DioCacheManager(CacheConfig(baseUrl: "http://www.google.com")).interceptor);
复制代码
options: buildCacheOptions(
Duration(days: 7),
forceRefresh: true,
options: Options(
headers: headers,
method: method,
extra: {
'needLoading': needLoading ?? true,
...(extra ?? {}),
},
),
)
复制代码
为何 toast 还须要使用单独的库呢?由于在 flutter 中,要显示 toast 的话,通常都须要使用到 BuildContext context
,而使用这个库的话,只须要用 BotToastInit
控件包裹一次,以后就能够直接使用了;不然就须要创建一个全局变量的 context(不知道是否可行)或是每次都传入 context。
在 flutter的initState
声明周期中,能够获得 context,但没法真正使用它,由于框架尚未彻底将其与 state 关联。直到 initState()
方法执行完成,State 对象就被初始化而且 context 变为可用。因此在 initState
方法中进行 http 请求时,不能直接显示 toast。
// 第一帧 build 结束时触发,此时context可用
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((callback){
});
}
复制代码
dependencies:
bot_toast: ^2.1.0
复制代码
import 'package:bot_toast/bot_toast.dart';
复制代码
// 1.使用BotToastInit直接包裹MaterialApp
BotToastInit(
child: MaterialApp(
title: 'BotToast Demo',
// 2.注册路由观察者
navigatorObservers: [BotToastNavigatorObserver()],
home: XxxxPage(),
)
);
复制代码
BotToast.showText(text:"xxxx"); //弹出一个文本框;
复制代码
BotToast.showSimpleNotification(title: "init"); //弹出简单通知Toast
复制代码
BotToast.showLoading(); //弹出一个加载动画
复制代码
dependencies:
flutter_easyrefresh: ^2.0.4
复制代码
不得不说,这个库真是至关的方便,比 web 端写起来要简单的多了。官方文档写的已经很详细了,我就不写了。
dependencies:
flutter_swiper: ^1.1.6
复制代码
这个库也是很强大了,基本上经常使用的功能都有。
若是要实现 tab 与 swiper 联动的话,
// swiper onIndexChanged
Swiper(
itemCount: 2,
itemBuilder: (context, index) {
return Container(
color: Color(0xFF82B1FF),
child: Center(child: Text('$index',)),
);
},
onIndexChanged: (index) {
_tabController.index = index;
},
controller: _swiperController,
)
// tab onTap
TabBar(
tabs: tabs,
labelPadding: EdgeInsets.only(bottom: 12.0),
indicatorSize: TabBarIndicatorSize.label,
indicatorWeight: 3.0,
onTap: (int index) {
_swiperController.move(index);
},
controller: _tabController,
)
复制代码
flutter 的状态管理库仍是挺多的,好比官方推荐的 Provider,还有 redux,mobx,bloc,rxdart 等,主要是目前的项目还很小,须要状态共享的地方很少,我就用 event bus 先凑合了。
dependencies:
event_bus: 1.1.0
复制代码
import 'package:event_bus/event_bus.dart';
EventBus eventBus = EventBus();
复制代码
class PieceEvent {
bool isBlack;
PieceEvent({ this.isBlack = true });
}
复制代码
eventBus.on<PieceEvent>().listen((event) {
setState(() {
isBlack = event.isBlack;
});
});
复制代码
eventBus.fire(PieceEvent(isBlack: isBlack));
复制代码
代码地址: github.com/ma125120/fl…