Flutter+Mobx実戦、アプリを書く
説明
現在、ルーティングジャンプが追加され、パラメータ付きジャンプページが表示されます.ドロップダウンはリフレッシュスタイルをカスタマイズでき、IOSは
プロジェクトのアドレス:https://github.com/Tecode/flutter_book、不定期の更新、startを歓迎します.
Androidプレビュー
IOSプレビュー
依存ライブラリ
システムステータスバーの色の変更
カスタムappBar左側ナビゲーション表示の内容
メディアクエリ
リソース構成
ルーティング構成
ここで私は
ルーティングに対応するモジュールを構成するには、
ここでは、渡されたパラメータをいくつか処理し、クラスにパラメータをインスタンス化します.
ルーティングを
使用
ルーティングパラメータ
ルーティングは中国語文字をサポートしていません符号化再復号が必要です
エンコーディング
デコード
Mobxステータスマネージャの使用
pubspec.yaml構成
複数のページに1つのstoreを使用
ここでは
使用方法
私のナビゲーションはその欄と下の内容が分かれていることを発見しました.ナビゲーションの切り替えボタンをクリックすると、表示されているページが変わります.そうすれば、表示層の
どうやって実現したか見てみましょう
クリックしてデータ
ナビゲーション
コンテンツ
に注意
最初のページ
2ページ目
どうやって解決しますか?前に述べた
共通のStore
正しい使い方
ページ1-ナビゲーションバー
ページ2-コンテンツ
パブリックストア
MobxとFlutterを関連付ける
終わりの言葉
あなたの周りを见てくれてありがとう.今は私が
画像のアップロードに失敗しました...(image-746 f 90-157908537541)
現在、ルーティングジャンプが追加され、パラメータ付きジャンプページが表示されます.ドロップダウンはリフレッシュスタイルをカスタマイズでき、IOSは
Status Bar
をクリックして上部に戻り、現在テストされています.ステータスマネージャはMobx
を使用していますが、Redux
を使用すると複雑になると思います.以下はプレビューGIF図ですが、カートン現象はスクリーン録画のフレームレートが少し低いためです.プロジェクトのアドレス:https://github.com/Tecode/flutter_book、不定期の更新、startを歓迎します.
Androidプレビュー
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\routers\routers.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> params) {
print("ROUTE WAS NOT FOUND !!!");
});
router.define(root, handler: rootHandler);
router.define(setting, handler: settingRouteHandler);
router.define(detail, handler: detailRouterHandler);
}
}
lib\routers\route_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> params) {
return FirstScreen();
});
Handler settingRouteHandler = Handler(
handlerFunc: (BuildContext context, Map> params) {
return Setting();
});
Handler detailRouterHandler = Handler(
handlerFunc: (BuildContext context, Map> params) {
return Detail(
title: FluroConvertUtils.fluroCnParamsDecode(params["title"]?.first));
});
lib\main.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?title=${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 = [];
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?title=${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> params) {
return Detail(
title: FluroConvertUtils.fluroCnParamsDecode(params["title"]?.first));
});
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:
複数のページに1つのstoreを使用
ここでは
provider: ^2.0.1
、React
のProvider
に使用します.Provider
を使用して、私たちのコンポーネントを包み、Mobx
と私たちのReact
を結びつけます.React Provider
Dart 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.dart
import '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
? AppColors.fontColor
: AppColors.fontColorGray),
),
),
IconButton(
alignment: Alignment.centerLeft,
onPressed: () {
findStore.setTile('tile', false);
},
icon: SvgPicture.asset(
'assets/icon/icon_cube.svg',
width: Constants.appBarIconSize + 2.0,
height: Constants.appBarIconSize + 2.0,
color: Color(findStore.tile
? AppColors.fontColorGray
: AppColors.fontColor),
),
),
],
centerTitle: 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 {
@override
Widget build(BuildContext context) {
final findStore = Provider.of(context);
return Observer(builder: (_) => findStore.tile ? BookTile() : BookCover());
}
}
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),
),
);
}
}
2ページ目
demo2.dart
このページにはcounter.dart
もインポートされています.私たちが望んでいる結果は、最初のページのデータが変化してもこのページに影響しますが、明らかにできません.store
は1つですが、インスタンス化するときは2つ違うので、最初のページのデータが変わってもここまでは影響しません.どうやって解決しますか?前に述べた
Provider
を使用して、Mobx
とFlutter
を結びつけ、上下関係を通じて私たちが望んでいるStore
、例えばfinal findStore = Provider.of(context);
に行くことができます.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-コンテンツ
パブリックストア
MobxとFlutterを関連付ける
終わりの言葉
あなたの周りを见てくれてありがとう.今は私が
Flutter
を书いて出会ったいくつかの穴です.みんなを歓迎して穴を踏んで、みんなはどんな意见と提案があっても提出することができます.ありがとうございます.画像のアップロードに失敗しました...(image-746 f 90-157908537541)