最近時間比較多,就把項目中可能用到的知識用 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…