1. 程式人生 > 實用技巧 >Flutter 學習筆記1【狀態共享】 mobx

Flutter 學習筆記1【狀態共享】 mobx

Flutter 中應用Mobx 實現全域性狀態共享

一.引入依賴

使用mobx, flutter_mobx, mobx_codegen, build_runner

pubspec.yaml

...
dependencies
mobx: ^1.2.1+4
flutter_mobx: ^1.1.0+2
...
dev_dependencies
build_runner: ^1.10.6
mobx_codegen: ^1.1.2

二.建立store檔案

儲存對應頁面的狀態

專案介面大致如下(按自己風格)

xxxproject/
lib/
...
store/
...
tabs.dart

三.編輯tabs.dart

tabs.dart

import 'package:mobx/mobx.dart';

/** 用於生成 tabsStore.g.dart **/
part 'tabsStore.g.dart';
class TabsStore = TabsStoreMobx with _$TabsStore;
/** 用於生成 tabsStore.g.dart **/

abstract class TabsStoreMobx with Store {
@observable
int bIndex = 0;
// TODO:陣列型別的需要使用ObservableList型別, 目前沒用到,暫時記錄
@observable
ObservableList tabsList = ObservableList();
@action
void changeIndex(newIndex) {
bIndex = newIndex;
}
@computed
double get doubleTypeIndex => bIndex.toDouble();
}

// 單例使用tabsStore
TabsStore tabsStore = TabsStore();

四.生成*.g.dart檔案

使用build_runner及mobx_codegen

在專案目錄下使用終端執行指令:

首次
flutter packages pub run build_runner build
每次修改到這個儲存store狀態的檔案後,都要刪除*.g.dart檔案,所以執行下面這個會方便一點
flutter packages pub run build_runner build --delete-conflicting-outputs
或者監聽store目錄的變化,自動生成
flutter packages pub run build_runner watch
此時的專案目錄如下
xxxproject/
lib/
...
store/
...
tabs.dart
tabs.g.dart

五.正式使用mobx

我想實現一個tabbar功能, 使用BottomAppBar, 每個tabs按鈕使用封裝好元件作為子元件

父元件 Tabs.dart

import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter_salted_fish/components/BottomAppBarItem.dart';
import 'package:flutter_salted_fish/pages/tabs/AddAction.dart';
import 'package:flutter_salted_fish/pages/tabs/Home.dart';
import 'package:flutter_salted_fish/pages/tabs/Mine.dart';
import 'package:flutter_salted_fish/pages/tabs/Msg.dart';
import 'package:flutter_salted_fish/pages/tabs/PlayGood.dart';
import 'package:flutter_salted_fish/store/tabsStore.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class Tabs extends StatefulWidget {
Tabs({Key key}) : super(key: key);

@override
_TabsState createState() => _TabsState();
}

class _TabsState extends State<Tabs> {

// final tabsStore = TabsStore(); // 不能這樣用

// final Color _activeIconColor = Color.fromRGBO(255, 230, 15, 1);
final Color _activeIconColor = Colors.amber;
final Color _unselectedItemColor = Colors.grey;
final Color _splashColor = Color.fromRGBO(255, 230, 15, 1);
final List<Map> _bottomAppData = [
{
"label": "鹹魚",
"icon": IconData(0xeee1, fontFamily: "AliIcons"),
"index": 0,
},
{
"label": "會玩",
"icon": IconData(0xef31, fontFamily: "AliIcons"),
"index": 1,
},
{
"label": "新增",
"icon": Icons.add,
"index": 2,
},
{
"label": "訊息",
"icon": IconData(0xeeda, fontFamily: "AliIcons"),
"index": 3,
},
{
"label": "我的",
"icon": IconData(0xeee5, fontFamily: "AliIcons"),
"index": 4,
},
];
List<Widget> _pageList = [
Home(),
PlayGoodPage(),
AddAction(),
MsgPage(),
Mine()
];
List<Widget> _generateBottomAppBarItem() {
return this._bottomAppData.map((item) {
return item["index"] == 2
? SizedBox()
: BottomAppBarItem(
iconData: item["icon"],
label: item["label"],
index: item["index"],
);
}).toList();
}

@override
void initState() {
super.initState();
setState(() {});
}

@override
Widget build(BuildContext context) {
ScreenUtil.init(
context,
designSize: Size(750, 1334),
allowFontScaling: false,
);
return Observer(
builder: (_) => Scaffold(
body: this._pageList[tabsStore.babIndex],
bottomNavigationBar: BottomAppBar(
notchMargin: ScreenUtil().setWidth(10.0),
color: Colors.white,
shape: CircularNotchedRectangle(), // 底部導航欄打一個圓形的洞
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, //均分底部導航欄橫向空間
children: this._generateBottomAppBarItem(),
),
),
floatingActionButton: Stack(
alignment: Alignment.bottomCenter,
children: [
FloatingActionButton(
child: Icon(Icons.add, color: Colors.black, size: 24),
foregroundColor: this._activeIconColor,
backgroundColor: this._activeIconColor,
focusColor: Colors.amber,
hoverColor: Colors.amber,
elevation: 0.0,
focusElevation: 0,
highlightElevation: 0,
splashColor: this._splashColor,
shape: RoundedRectangleBorder(
side: BorderSide(
width: 4,
color: this._activeIconColor,
),
borderRadius: BorderRadius.circular(30)),
onPressed: () {
tabsStore.changeIndex(2);
},
),
],
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
),
);
}
}

子元件 BottomAppBarItem.dart

import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter_salted_fish/store/tabsStore.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class BottomAppBarItem extends StatefulWidget {
var iconData = IconData(0xeee1, fontFamily: "AliIcons");
String label = '鹹魚';
int index = 0;
BottomAppBarItem(
{this.iconData,
this.label,
this.index,
Key key})
: super(key: key);

@override
_BottomAppBarItemState createState() => _BottomAppBarItemState();
}

class _BottomAppBarItemState extends State<BottomAppBarItem> {
// final tabsStore = TabsStore(); // 不能這樣用

@override
Widget build(BuildContext context) {
return Container(
child: InkWell(
onTap: () {
tabsStore.changeIndex(widget.index);
},
child: Container(
width: ScreenUtil().setWidth(126),
height: ScreenUtil().setHeight(90),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
widget.iconData,
color: tabsStore.babIndex == widget.index
? Colors.amber
: Colors.grey,
),
SizedBox(height: 4),
Text(
widget.label,
style: TextStyle(
color: tabsStore.babIndex == widget.index
? Colors.amber
: Colors.grey,
),
),
],
),
),
),
);
}
}

如果在父子元件中都使用 TabsStore tstore = TabsStore(), 則父子元件實際上用的不是同一個例項的狀態, 被這坑了一會