摘要:在這里可以處理一些傳過來的參數,然后我們將參數放入類中實例化。因為雖然是一個,但是實例化的時候是兩個不同的,所以第一個頁面的數據變化了也不會影響到這里。
說明目前增加了路由跳轉,可以帶參數跳轉頁面。下拉可以自定義刷新樣式,IOS點擊Status Bar回到頂部,目前已經測試過。狀態管理器使用Mobx,我自己覺得對于Redux使用起來會復雜一點,下面是提供的預覽GIF圖,卡頓現象是因為屏幕錄制的幀率有點低。
項目地址:github.com/Tecode/flut…,不定時的更新,歡迎start。
安卓預覽IOS預覽
依賴庫
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
mobx:
flutter_mobx: // Mobx
cupertino_icons: ^0.1.2
flutter_svg: ">=0.12.4" // 處理SVG圖片
carousel_slider: ^1.3.0 // 輪播圖
fluro: "^1.4.0" // 路由
provider: ^2.0.1 // 用于包裹mobx
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.3.1 //Mobx依賴
mobx_codegen: // Mobx依賴
Flutter版本
Flutter 1.5.9-pre.223 ? channel master ? https://github.com/flutter/flutter.git
Framework ? revision b76a1e8312 (25 hours ago) ? 2019-05-13 09:06:30 +0100
Engine ? revision 816d3fc586
Tools ? Dart 2.3.1 (build 2.3.1-dev.0.0 a0290f823c)
修改系統狀態欄顏色
import "package:flutter/material.dart";
import "package:flutter/cupertino.dart";
import "package:flutter_book/containers/Entrance.dart";
import "package:flutter_book/helpers/constants.dart" show AppColors;
import "package:flutter/services.dart";
void main() {
// 修改系統狀態欄顏色
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
systemNavigationBarColor: Color(AppColors.themeColor), // navigation bar color
statusBarColor: Color(AppColors.themeColor), // status bar color
));
runApp(MyApp());wenti
}
自定義appBar左側導航顯示的內容
appBar: AppBar(
...
leading: IconButton(
alignment: Alignment.centerRight,
icon: SvgPicture.asset(
"assets/icon/icon_trophy.svg",
width: Constants.appBarIconSize + 5.0,
height: Constants.appBarIconSize + 5.0,
),
onPressed: () {
print("ok");
},
)
...
)
媒體查詢
MediaQuery.of(context)資源配置
assets: - assets/icon/ - lib/containers/ - lib/model/ - lib/helpers/ - lib/routers/ - assets/images/路由配置
這里我使用的是fluro配置路由,這里我偷一下懶了,就沒有使用原生的方法,不過他幫我們封裝了好多的方法我們可以很方便的去使用它,下面說一下路由的配置。
lib outers outers.dart配置路由對應的模塊,可以理解成Vue-router或React-router一樣,先要將對應的路由配置到你要跳轉的模塊去。
import "package:fluro/fluro.dart";
import "package:flutter/material.dart";
import "package:flutter_book/routers/route_handlers.dart";
class Routes {
static String root = "/";
static String setting = "/setting";
static String detail = "/detail";
static String demoSimpleFixedTrans = "/demo/fixedtrans";
static String demoFunc = "/demo/func";
static String deepLink = "/message";
static void configureRoutes(Router router) {
router.notFoundHandler = Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
print("ROUTE WAS NOT FOUND !!!");
});
router.define(root, handler: rootHandler);
router.define(setting, handler: settingRouteHandler);
router.define(detail, handler: detailRouterHandler);
}
}
lib
outers
oute_handlers.dart
在這里可以處理一些傳過來的參數,然后我們將參數放入類中實例化。
import "package:flutter_book/containers/Setting.dart";
import "package:flutter_book/containers/FirstScreen.dart";
import "package:flutter_book/containers/Detail.dart";
import "package:fluro/fluro.dart";
import "package:flutter/material.dart";
import "package:flutter_book/helpers/fluro_convert_util.dart";
Handler rootHandler = Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return FirstScreen();
});
Handler settingRouteHandler = Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return Setting();
});
Handler detailRouterHandler = Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return Detail(
title: FluroConvertUtils.fluroCnParamsDecode(params["title"]");
libmain.dart
將路由與Flutter綁定,這樣你的路由就可以生效了
class MyApp extends StatelessWidget {
MyApp() {
final router = new Router();
Routes.configureRoutes(router);
Application.router = router;
}
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter Book",
theme: ThemeData(
primaryColor: Color(AppColors.themeColor),
accentColor: Color(AppColors.themeColor),
scaffoldBackgroundColor: Color(AppColors.themeColor)),
home: Entrance(),
onGenerateRoute: Application.router.generator,
);
}
}
使用
import "package:fluro/fluro.dart";
import "package:flutter_book/routers/application.dart";
import "package:flutter_book/helpers/fluro_convert_util.dart";
...代碼省略了
Application.router.navigateTo(
context,
"/detail");${FluroConvertUtils.fluroCnParamsEncode("熱門圖書")}",
transition: TransitionType.native
);
路由傳參
路由不支持中文字符需要編碼再解碼
import "dart:convert";
/// fluro 參數編碼解碼工具類
class FluroConvertUtils {
/// fluro 傳遞中文參數前,先轉換,fluro 不支持中文傳遞
static String fluroCnParamsEncode(String originalCn) {
StringBuffer sb = StringBuffer();
var encoded = Utf8Encoder().convert(originalCn);
encoded.forEach((val) => sb.write("$val,"));
return sb.toString().substring(0, sb.length - 1).toString();
}
/// fluro 傳遞后取出參數,解析
static String fluroCnParamsDecode(String encodedCn) {
var decoded = encodedCn.split("[").last.split("]").first.split(",");
var list = <int>[];
decoded.forEach((s) => list.add(int.parse(s.trim())));
return Utf8Decoder().convert(list);
}
}
編碼
import "package:flutter_book/helpers/fluro_convert_util.dart";
Application.router.navigateTo(
context,
"/detail");${FluroConvertUtils.fluroCnParamsEncode("熱門圖書")}",
transition: TransitionType.native,
// transitionDuration: const Duration(milliseconds: 300),
);
解碼
import "package:flutter_book/helpers/fluro_convert_util.dart";
Handler detailRouterHandler = Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return Detail(
title: FluroConvertUtils.fluroCnParamsDecode(params["title"]");
使用Mobx狀態管理器
pubspec.yaml配置
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
mobx:
flutter_mobx:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
flutter_svg: ">=0.12.4"
carousel_slider: ^1.3.0
fluro: "^1.4.0"
provider: ^2.0.1
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.3.1
mobx_codegen:
多個頁面使用一個store
這里要使用到provider: ^2.0.1,類似React的Provider。使用Provider來包裹我們的組件,使Mobx和我們的React聯系起來。
React ProviderDart Provider
Dart Provider也是一樣的道理,將Mobx和Flutter聯系起來,lib/main.dart完整代碼,這樣使用可以保證你實例化的的store是同一個類。
runApp(MultiProvider( providers: [ Provider如何使用( builder: (_) => FindStore(), ) ], child: MyApp(), ));
我的導航發現那一欄和下面的內容是分開的,當我點擊導航的切換按鈕就會改變顯示的頁面,這樣我們可以復用顯示層的UI組件,數據放專門的文件去管理。
來看看如何實現的
通過點擊然后改變數據findStore.setTile("tile", true);
導航lib/widgets/NavBar/FindNavBar.dartimport "package:flutter/material.dart";
import "package:flutter_svg/svg.dart";
import "package:flutter_mobx/flutter_mobx.dart";
import "package:flutter_book/helpers/constants.dart";
import "package:flutter_book/stores/findStore.dart";
import "package:provider/provider.dart";
class FindNavBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 我們的store
final findStore = Provider.of(context);
return Observer(
builder: (_) => AppBar(
title: Text("發現"),
actions: [
IconButton(
alignment: Alignment.centerRight,
onPressed: () {
findStore.setTile("tile", true);
findStore.counter();
},
icon: SvgPicture.asset(
"assets/icon/icon_more.svg",
width: Constants.appBarIconSize + 2.0,
height: Constants.appBarIconSize + 2.0,
color: Color(findStore.tile
");"tile", false);
},
icon: SvgPicture.asset(
"assets/icon/icon_cube.svg",
width: Constants.appBarIconSize + 2.0,
height: Constants.appBarIconSize + 2.0,
color: Color(findStore.tile
");true,
elevation: 0,
),
);
}
}
內容lib/containers/Find.dart
檢測到數據發生變化,頁面重新渲染得到新的頁面
import "package:flutter/material.dart";
import "package:flutter_book/widgets/Find/BookTile.dart";
import "package:flutter_book/widgets/Find/BookCover.dart";
import "package:flutter_book/stores/findStore.dart";
import "package:provider/provider.dart";
import "package:flutter_mobx/flutter_mobx.dart";
class Find extends StatefulWidget {
@override
_FindState createState() => _FindState();
}
class _FindState extends State<Find> {
@override
Widget build(BuildContext context) {
final findStore = Provider.of(context);
return Observer(builder: (_) => findStore.tile ");
FindStore lib/stores/findStore.dart
import "package:mobx/mobx.dart";
// Include generated file
part "findStore.g.dart";
// This is the class used by rest of your codebase
class FindStore = _FindStore with _$FindStore;
// The store-class
abstract class _FindStore implements Store {
@observable
bool tile = false;
@observable
num count = 0;
@action
void setTile(String key, dynamic value) => tile = value;
@action
num counter() => this.count++;
}
注意
如果你是很多個頁面共享一個Store不要直接導入然后實例化,例如:
第一個頁面 demo1.dart這個頁面我們導入了counter.dart這個store而且我們將它實例化,當我們點擊的時候數據發生變化頁面會重新渲染
import "package:flutter/material.dart";
import "package:flutter_mobx/flutter_mobx.dart";
import "counter.dart"; // Import the Counter
final counter = Counter(); // Instantiate the store
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "MobX",
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("MobX Counter"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"數值是:",
),
// Wrapping in the Observer will automatically re-render on changes to counter.value
Observer(
builder: (_) => Text(
"${counter.value}",
style: Theme.of(context).textTheme.display1,
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: counter.increment,
tooltip: "Increment",
child: Icon(Icons.add),
),
);
}
}
第二個頁面 demo2.dart
這個頁面我們也導入了counter.dart,我們要的結果是第一個頁面的數據變化了也影響這個頁面,但是顯然是不能的。因為store雖然是一個,但是實例化的時候是兩個不同的,所以第一個頁面的數據變化了也不會影響到這里。
怎么解決呢?我們可以使用之前提到的Provider去將Mobx與Flutter聯系起來然后通過上下關系去的到我們想要的Store,例如final findStore = Provider.of
import "package:flutter/material.dart";
import "package:flutter_mobx/flutter_mobx.dart";
import "counter.dart"; // Import the Counter
final counter = Counter(); // Instantiate the store
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "MobX",
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("MobX Counter"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"第二個頁面顯示第一個頁面的數是:",
),
Observer(
builder: (_) => Text(
"${counter.value}",
style: Theme.of(context).textTheme.display1,
),
),
],
),
),
);
}
}
公共的Store counter.dart
import "package:mobx/mobx.dart";
// Include generated file
part "counter.g.dart";
// This is the class used by rest of your codebase
class Counter = _Counter with _$Counter;
// The store-class
abstract class _Counter implements Store {
@observable
int value = 0;
@action
void increment() {
value++;
}
}
正確的使用方法
頁面1-導航欄
頁面2-內容
公共Store
將Mobx和Flutter聯系起來
結束語感謝你的圍觀,目前是我寫Flutter遇到的一些坑,歡迎大家一踩坑,大家有什么意見和建議都可以提出來,謝謝。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/7292.html
摘要:昨天有個小學弟給我發來微信,說他現在有點后悔選擇開發了,月月光不說,還加班特別嚴重,平時也沒有屬于自己的時間去學習,問我剛畢業的時候是不是這樣。每天回到出租屋都是倒頭就睡,非常累,也沒有其他時間提升自己的技術。 昨天有個小學弟給我發來微信,說他現在有點后悔選擇Android開發了,月月光不說...
摘要:前言最近比較熱門,但是成體系的文章并不多,前期避免不了踩坑我這篇文章主要介紹如何使用實現一個比較復雜的手勢交互,順便分享一下我在使用過程中遇到的一些小坑,減少大家入坑作者鏈接先睹為快本項目支持運行,效果如下對了,順便分享一下生成的小竅門,建 前言 Flutter最近比較熱門,但是Flutter成體系的文章并不多,前期避免不了踩坑;我這篇文章主要介紹如何使用Flutter實現一個比較復雜...
摘要:前言最近比較熱門,但是成體系的文章并不多,前期避免不了踩坑我這篇文章主要介紹如何使用實現一個比較復雜的手勢交互,順便分享一下我在使用過程中遇到的一些小坑,減少大家入坑作者鏈接先睹為快本項目支持運行,效果如下對了,順便分享一下生成的小竅門,建 前言 Flutter最近比較熱門,但是Flutter成體系的文章并不多,前期避免不了踩坑;我這篇文章主要介紹如何使用Flutter實現一個比較復雜...
閱讀 1982·2019-08-30 15:54
閱讀 3532·2019-08-30 15:52
閱讀 1822·2019-08-29 17:20
閱讀 2514·2019-08-29 17:08
閱讀 2346·2019-08-26 13:24
閱讀 780·2019-08-26 11:59
閱讀 2780·2019-08-23 14:50
閱讀 611·2019-08-23 14:20