Flutter MVVM架构辅助插件mvvm_builder的使用

Flutter MVVM架构辅助插件mvvm_builder的使用


插件介绍

mvvm_builder 是一个用于帮助开发者在 Flutter 中实现 MVVM(Model-View-ViewModel)设计模式的插件。MVVM 模式将业务逻辑与视图分离,使代码更易于测试和维护。


安装

要使用该插件,请将其添加到 pubspec.yaml 文件中:

dependencies:
  mvvm_builder: ^版本号

然后运行以下命令安装依赖:

flutter pub get

为什么使用 MVVM 设计模式?

MVVM 设计模式广泛应用于 Android 和 iOS 原生开发中。它是一种优秀的复杂页面解决方案,能够编写可测试的代码并提高性能。

主要优点:

  • 将业务逻辑从视图中分离。
  • 提高代码的可读性和可维护性。
  • 便于单元测试。

使用方法

1. 导入 MVVMPage Widget

首先导入 mvvm_builder 包:

import 'package:mvvm_builder/mvvm_builder.dart';

2. 创建 Model

定义数据模型类 MyViewModel 和其子类 TodoModel

class MyViewModel extends MVVMModel {
  String title;
  List<TodoModel> todoList;
}

class TodoModel {
  String title, subtitle;

  TodoModel(this.title, this.subtitle);
}

3. 创建 Presenter

创建一个 Presenter 类来处理业务逻辑:

class MyPresenter extends Presenter<MyViewModel, MyViewInterface> {

  MyPresenter(MyViewModel model, MyViewInterface view) : super(model, view);

  [@override](/user/override)
  Future onInit() async {
    // 初始化 ViewModel 数据
    this.viewModel.title = "My todo list";
    this.viewModel.todoList = List();
    for(int i = 0; i < 15; i++) {
      this.viewModel.todoList.add(new TodoModel("TODO $i", "my task $i"));
    }
    this.refreshView(); // 更新视图
  }
}

4. 定义 View 接口

定义一个接口 MyViewInterface 来描述视图的行为:

abstract class MyViewInterface {

  void showMessage(String message);

}

5. 创建页面

方法一:直接使用 MVVMPage

class _MyAppState extends State<MyApp> implements MyViewInterface {
  
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();

  [@override](/user/override)
  void initState() {
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MVVMPage<MyPresenter, MyViewModel>(
        builder: (context, presenter, model) {
          return Scaffold(
            appBar: AppBar(title: Text(model.title)),
            body: ListView.builder(
              itemCount: model.todoList.length,
              itemBuilder: (context, index) => ListTile(
                title: Text(model.todoList[index].title),
                subtitle: Text(model.todoList[index].subtitle),
              ),
            ),
          );
        },
        presenter: MyPresenter(new MyViewModel(), this),
      ),
    );
  }

  [@override](/user/override)
  void showMessage(String message) {
    _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message)));
  }
}

方法二:使用 MVVMPageBuilder

class MyAppWithBuilder extends StatelessWidget implements MyViewInterface {

  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
  final mvvmPageBuilder = MVVMPageBuilder<MyPresenter, MyViewModel>();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return mvvmPageBuilder.build(
      context: context,
      key: ValueKey("page"),
      presenterBuilder: (context) => MyPresenter(new MyViewModel(), this),
      builder: (context, presenter, model) {
        return Scaffold(
          appBar: AppBar(title: Text(model?.title ?? "")),
          body: ListView.separated(
            itemBuilder: (context, index) => InkWell(
              onTap: () => presenter.onClickItem(index),
              child: ListTile(
                title: Text(model.todoList[index].title),
                subtitle: Text(model.todoList[index].subtitle),
              ),
            ),
            separatorBuilder: (context, index) => Divider(height: 1),
            itemCount: model.todoList.length ?? 0,
          ),
        );
      },
    );
  }

  [@override](/user/override)
  void showMessage(String message) {
    _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message)));
  }
}

应用路由

为了保持页面状态,推荐使用 MVVMPageBuilder 并结合路由:

final homePageBuilder = MyAppWithBuilder();

Route<dynamic> route(RouteSettings settings) {
  print("...[call route] ${settings.name}");
  switch (settings.name) {
    case "/":
      return MaterialPageRoute(builder: homePageBuilder.build);
  }
}

void main() {
  print("...[main]");
  runApp(
    MaterialApp(
      onGenerateRoute: route,
    ),
  );
}

测试

MVVM 模式非常适合单元测试,因为它将业务逻辑与视图分离。你可以单独测试 ViewModel 和 Presenter,并且可以轻松模拟不同的 ViewModel 状态。


使用动画

MVVMPage 支持动画效果,可以通过以下方式实现:

class MyApp extends StatelessWidget implements MyViewInterface {

  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
  final MyPresenter mPresenter = MyPresenter.create(null);

  MyApp() {
    mPresenter.init(this);
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MVVMPage<MyPresenter, MyViewModel>(
        builder: (context, presenter, model) {
          var animation = CurvedAnimation(
            parent: context.animationController,
            curve: Curves.easeIn,
          );
          return Scaffold(
            key: _scaffoldKey,
            appBar: AppBar(title: Text(model.title)),
            body: ListView.separated(
              itemBuilder: (context, index) => InkWell(
                onTap: () => presenter.onClickItem(index),
                child: AnimatedBuilder(
                  animation: animation,
                  builder: (context, child) => Opacity(opacity: animation.value, child: child),
                  child: ListTile(
                    title: Text(model.todoList[index].title),
                    subtitle: Text(model.todoList[index].subtitle),
                  ),
                ),
              ),
              separatorBuilder: (context, index) => Divider(height: 1),
              itemCount: model.todoList.length,
            ),
          );
        },
        presenter: mPresenter,
        singleAnimControllerBuilder: (tickerProvider) => AnimationController(vsync: tickerProvider, duration: Duration(seconds: 1)),
        animListener: (context, presenter, model) {
          if(model.fadeInAnimation) {
            context.animationController
              .forward()
              .then((value) => presenter.onFadeInAnimationEnd());
          }
        },
      ),
    );
  }

  [@override](/user/override)
  void showMessage(String message) {
    _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message)));
  }
}

更多关于Flutter MVVM架构辅助插件mvvm_builder的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter MVVM架构辅助插件mvvm_builder的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


mvvm_builder 是一个用于简化 Flutter 应用中 MVVM(Model-View-ViewModel)架构实现的辅助插件。它通过自动生成一些模板代码,帮助开发者更高效地构建 MVVM 架构的 Flutter 应用。

以下是 mvvm_builder 插件的基本使用步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 mvvm_builder 插件的依赖:

dependencies:
  mvvm_builder: ^latest_version

然后运行 flutter pub get 来获取依赖。

2. 创建 ViewModel

mvvm_builder 插件要求你创建一个 ViewModel 类,通常这个类会继承自 ChangeNotifierBaseViewModel(如果插件提供了这个基类)。

import 'package:flutter/material.dart';

class MyViewModel extends ChangeNotifier {
  String _data = "Hello, MVVM!";

  String get data => _data;

  void updateData(String newData) {
    _data = newData;
    notifyListeners();
  }
}

3. 创建 View

接下来,你需要创建一个 View,通常是一个 StatelessWidgetStatefulWidgetmvvm_builder 插件会帮助你自动生成一些代码来绑定 ViewViewModel

import 'package:flutter/material.dart';
import 'package:mvvm_builder/mvvm_builder.dart';
import 'my_view_model.dart';

class MyView extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MVVMBuilder<MyViewModel>(
      viewModel: MyViewModel(),
      builder: (context, viewModel, child) {
        return Scaffold(
          appBar: AppBar(
            title: Text('MVVM Example'),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(viewModel.data),
                ElevatedButton(
                  onPressed: () {
                    viewModel.updateData("Data Updated!");
                  },
                  child: Text('Update Data'),
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

4. 使用 MVVMBuilder

MVVMBuildermvvm_builder 插件提供的一个 Widget,它负责将 ViewViewModel 绑定在一起。你只需要在 View 中使用 MVVMBuilder,并传入 ViewModel 实例即可。

5. 运行应用

现在你可以运行你的 Flutter 应用,MVVMBuilder 会自动处理 ViewViewModel 之间的绑定和状态更新。

6. 其他功能

mvvm_builder 插件可能还提供其他功能,例如自动生成 ViewModelView 的模板代码、依赖注入等。你可以查看插件的文档以了解更多高级用法。

7. 注意事项

  • 确保 ViewModel 继承自 ChangeNotifier 或插件提供的基类,以便能够通知 View 进行更新。
  • MVVMBuilder 会自动处理 ViewModel 的生命周期,你不需要手动管理 ViewModel 的创建和销毁。

8. 示例代码

以下是一个完整的示例代码:

import 'package:flutter/material.dart';
import 'package:mvvm_builder/mvvm_builder.dart';

class MyViewModel extends ChangeNotifier {
  String _data = "Hello, MVVM!";

  String get data => _data;

  void updateData(String newData) {
    _data = newData;
    notifyListeners();
  }
}

class MyView extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MVVMBuilder<MyViewModel>(
      viewModel: MyViewModel(),
      builder: (context, viewModel, child) {
        return Scaffold(
          appBar: AppBar(
            title: Text('MVVM Example'),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(viewModel.data),
                ElevatedButton(
                  onPressed: () {
                    viewModel.updateData("Data Updated!");
                  },
                  child: Text('Update Data'),
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

void main() {
  runApp(MaterialApp(
    home: MyView(),
  ));
}
回到顶部