ViewModel X
一个类似Android的state management包,可轻松实现MVVM模式。
注意: 在Android中,ViewModel具有在配置更改时保留状态的特殊功能。此包中的ViewModel不是为此目的设计的,因为Flutter项目不需要它。它仅用于将View Logic与UI分离。
? 示例项目的实时演示: https://shubham-gupta-16.github.io/view_model_x/
功能
- 简化的 ? 状态管理
- 与Android项目相似的代码模式 ?
- 方便开发者从Android迁移到Flutter ?️
- 允许开发者轻松地同时处理Android和Flutter项目 ?
- 易于实现MVVM模式 ?
软件包组件
- StateFlow, MutableStateFlow (相当于LiveData) ⛵
- SharedFlow, MutableSharedFlow ?
- ViewModel (将视图逻辑与UI分离,类似于Cubit)
- ViewModelProvider
- StateFlowBuilder
- StateFlowConsumer
- StateFlowListener
- SharedFlowListener
- MultiFlowListener
- ChangeNotifierProvider
- MultiProvider
用法
my_view_model.dart
class CounterViewModel extends ViewModel {
// initialize MutableStateFlow with initial value 1
final _counterStateFlow = MutableStateFlow<int>(1);
StateFlow<int> get counterStateFlow => _counterStateFlow;
// you can also define more the one StateFlow or SharedFlow inside any ViewModel
void increment() {
// by changing the value, listeners notified
_counterStateFlow.value = _counterStateFlow.value + 1;
}
@override
void dispose() {
// must dispose all the StateFlows and SharedFlows
_counterStateFlow.dispose();
}
}
main.dart
void main() => runApp(CounterApp());
class CounterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ViewModelProvider(
create: (_) => CounterViewModel(),
child: CounterPage(),
),
);
}
}
counter_page.dart
class CounterPage extends StatelessWidget {
const CounterPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('ViewModel Counter Example')),
body: Center(
// implement StateFlowBuilder to rebuild Text on StateFlow value changed/updated
child: StateFlowBuilder(
// pass your StateFlow
stateFlow: context.vm<CounterViewModel>().counterStateFlow,
builder: (context, value) {
return Text("$value", style: const TextStyle(fontSize: 30));
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// call the increment function which is inside MyViewModel
ViewModelProvider.of<CounterViewModel>(context).increment();
},
child: const Icon(Icons.add),
),
);
}
}
软件包组件
ViewModel (创建自定义ViewModel类)
创建您的自定义View-Model,它必须继承自ViewModel。在其中声明所有Flow和与View相关的逻辑。不要忘记在ViewModel的dispose方法中处理所有Flow。
class CustomViewModel extends ViewModel {
// initialize StateFlow
final _myStateFlow = MutableStateFlow<int>(1);
StateFlow<int> get myStateFlow => _myStateFlow;
// view related logic here
@override
void dispose() {
// must dispose all flows
_myStateFlow.dispose();
}
}
PostFrameCallback 与 ViewModel
这将有助于在ViewModel中轻松获取onPostFrameCallback事件。通过使用PostFrameCallback,我们可以从
WidgetsBinding.instance.addPostFrameCallback((_){
// do stuffs here
})
to
class CustomViewModel extends ViewModel with PostFrameCallback {
//...
@override
void onPostFrameCallback(Duration timestamp) {
// do stuffs here
}
}
MutableStateFlow 和 StateFlow
MutableStateFlow继承自StateFlow。它存储值并在值更改时通知监听器。它可以更改/更新值。
建议初始化私有的
MutableStateFlow,并为其创建公共的StateFlowgetter。
final _myStateFlow = MutableStateFlow<int>(1, notifyOnSameValue: true);
StateFlow<int> get myStateFlow => _myStateFlow;
在此,notifyOnSameValue是可选的。如果将notifyOnSameValue设置为false,每当您调用stateFlow.value = newValue(其中newValue与当前值相同)时,它都不会通知监听器。默认情况下设置为true。
更改值
_myStateFlow.value = 5; // listeners were automatically notified
更新值
_listStateFlow.update((value) {
value.add(obj);
}); // listeners were automatically notified
MutableSharedFlow 和 SharedFlow
MutableSharedFlow继承自SharedFlow。它用于将数据发送到监听器。它可以发射值。
建议初始化私有的
MutableSharedFlow,并为其创建公共的SharedFlowgetter。
final _mySharedFlow = MutableSharedFlow<String>();
SharedFlow<int> get mySharedFlow => _mySharedFlow;
发射值
_myStateFlow.emit("Hello from ViewModel!"); // listeners were automatically notified
将ViewModel集成到Flutter Widget中
ViewModelProvider
ViewModelProvider用于将Widget包装在您的自定义ViewModel中。这需要create,它接受自定义ViewModel和child Widget。
ViewModelProvider(
create: (context) => counterViewModel, // provide your custom viewModel
child: ChildWidget(),
);
在Widget Tree中获取ViewModel实例
ViewModelProvider.of<CustomViewModel>(context)
或者
context.vm<CustomViewModel>()
Builder, Listener, and Consumer Flutter Widgets
StateFlowBuilder
StateFlowBuilder用于重建其中的Widgets。这需要stateFlow来监听,以及builder,当stateFlow的值更改/更新时会重建。
StateFlowBuilder(
stateFlow: context.vm<CustomViewModel>().myStateFlow, // pass StateFlow
builder: (context, value) {
return ChildWidget(value); // rebuild the widget with updated/changed value.
},
)
StateFlowConsumer
StateFlowConsumer用于重建其中的Widgets并调用监听器。这需要stateFlow来监听,builder和listener。每当stateFlow的值更改/更新时,builder将重建其中的Widgets,而listener将被调用。
StateFlowConsumer(
stateFlow: ViewModelProvider.of<CustomViewModel>(context).myStateFlow, // pass SharedFlow
listener: (context, value) {
// do stuff here based on value
},
builder: (context, value) {
return ChildWidget(value); // rebuild the widget with updated/changed value.
},
)
StateFlowListener
StateFlowListener用于捕获stateFlow的更改/更新值事件。这需要stateFlow、listener和child。每当stateFlow的值更改/更新时,listener将被调用。
StateFlowListener(
stateFlow: ViewModelProvider.of<CustomViewModel>(context).myStateFlow, // pass StateFlow
listener: (context, value) {
// do stuff here based on value
},
child: ChildWidget(),
)
SharedFlowListener
SharedFlowListener用于捕获sharedFlow发射的值。这需要sharedFlow、listener和child。每当sharedFlow发射值时,listener将被调用。
SharedFlowListener(
sharedFlow: ViewModelProvider.of<CustomViewModel>(context).mySharedFlow, // pass SharedFlow
listener: (context, value) {
// do stuff here based on value
},
child: ChildWidget(),
)
MultiFlowListener
MultiFlowListener是一个Flutter Widget,它合并了多个SharedFlowListener和StateFlowListener Widget。MultiFlowListener提高了可读性,并消除了嵌套多个监听器的需要。通过使用MultiFlowListener,我们可以从
SharedFlowListener(
sharedFlow: context.vm<ViewModelA>().mySharedFlow,
listener: (context, value) {
// do stuff here based on value
},
child: StateFlowListener(
stateFlow: context.vm<ViewModelA>().myStateFlow,
listener: (context, value) {
// do stuff here based on value
},
child: SharedFlowListener(
sharedFlow: context.vm<ViewModelB>().anySharedFlow,
listener: (context, value) {
// do stuff here based on value
},
child: ChildA(),
)
)
)
to
MultiFlowListener(
providers: [
SharedFlowListener(
sharedFlow: context.vm<ViewModelA>().mySharedFlow,
listener: (context, value) {
// do stuff here based on value
},
),
StateFlowListener(
stateFlow: context.vm<ViewModelA>().myStateFlow,
listener: (context, value) {
// do stuff here based on value
},
),
SharedFlowListener(
sharedFlow: context.vm<ViewModelB>().anySharedFlow,
listener: (context, value) {
// do stuff here based on value
},
),
],
child: ChildA(),
)
附加Provider
此包还包含一些Provider组件,并进行了一些修改。它们是:
ChangeNotifierProvider
这将允许用ChangeNotifier包装Widget。
ChangeNotifierProvider(
create: (context) => CustomChangeNotifier(),
child: WidgetA(),
)
获取ChangeNotifier的实例或监听notifyListeners()
ChangeNotifierProvider.of<CustomChangeNotifier>(context, listen: true)
如果listen为true,Widget将在notifyListeners()时重建。也可以用更简洁的方式编写。如果想监听notifyListeners(),请使用:
context.watch<CustomChangeNotifier>()
或者如果只想获取实例,请使用:
context.read<CustomChangeNotifier>()
注意: 此处的
context.watch和context.read来自provider库的修改。在此,类型被限制为ChangeNotifier。
MultiProvider
MultiProvider是一个Widget,它合并了多个ViewModelProvider和ChangeNotifierProvider Widget。MultiProvider提高了可读性,并消除了嵌套多个Widget的需要。通过使用MultiProvider,我们可以从
ViewModelProvider(
create: (context) => ViewModelA(),
child: ViewModelProvider(
create: (context) => ViewModelB(),
child: ChangeNotifierProvider(
create: (context) => ChageNotifierA(),
child: ChildA(),
)
)
)
to
MultiProvider(
providers: [
ViewModelProvider(
create: (context) => ViewModelA(),
),
ViewModelProvider(
create: (context) => ViewModelB(),
),
ChageNotifierProvider(
create: (context) => ChageNotifierA(),
),
],
child: ChildA(),
)
注意: 此MultiProvider与Provider包中的不同。它只接受
ViewModelProvider和ChangeNotifierProvider。
贡献
欢迎 Pull requests。对于重大更改,请先打开一个 issue 来讨论您想进行的更改。