fast_mvvm 2.1.8 copy "fast_mvvm: ^2.1.8" to clipboard
fast_mvvm: ^2.1.8 copied to clipboard

Implemented using the MVVM architecture, quickly build projects to help consumers focus only on the business implementation

fast_mvvm #

博客讲解:https://blog.csdn.net/q948182974/article/details/106613565

掘金讲解:https://juejin.im/post/5ee86c9b51882543313a0de7

一个MVVM框架附带简单的demo,会一直更新,希望支持一下.有问题可以反馈QQ 275918180。

Demo 讲解 #

这里模拟了文章列表。 Model:UserModel BaseListViewModel: ArticleVM View:ArticlePage 数据实体类 BaseEntity:ArticleEntity 主要讲解了初始化配置, 状态页效果,根布局刷新,数据获取。

UserModel #

首先创建项目模块所需要用的Model,按大模块区分。 这里创建UserModel

class UserModel extends BaseModel {
  /// 登录
  Future<bool> login(String account, String psd) async {
    await Future.delayed(Duration(seconds: 3));
    return true;
  }

  /// 资讯列表
  Future<DataResponse<ArticleEntity>> getArticleList() async {
    await Future.delayed(Duration(seconds: 2));

    var entity = ArticleEntity([
      ArticleItem("1", "好的", "内容内容内容内容内容", DateTime.now().toString()),
      ArticleItem("1", "好的", "内容内容内容内容内容", DateTime.now().toString()),
    ]);

    DataResponse dataResponse =
        DataResponse<ArticleEntity>(entity: entity, totalPageNum: 3);
    return dataResponse;
  }
}

初始化 #

在APP首页启动的时候初始化框架。 调用initMVVM(),装载UserModel,配置上拉加载下拉刷新; 选择文章页面是否根布局刷新选项,是否配置单独的状态页。


class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  @override
  void initState() {
    initMVVM<BaseViewModel>(
      [UserModel()],
      controllerBuild: () => EasyRefreshController(),
      resetRefreshState: (c) =>
          (c as EasyRefreshController)?.resetRefreshState(),
      finishRefresh: (c, {bool success, bool noMore}) =>
          (c as EasyRefreshController)
              ?.finishRefresh(success: success, noMore: noMore),
      resetLoadState: (c) => (c as EasyRefreshController)?.resetLoadState(),
      finishLoad: (c, {bool success, bool noMore}) =>
          (c as EasyRefreshController)
              ?.finishLoad(success: success, noMore: noMore),
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: SelectPage(),
    );
  }
}

class SelectVM extends BaseViewModel {
  ValueNotifier<bool> isLoadData = ValueNotifier(true);
  ValueNotifier<bool> isConfigState = ValueNotifier(false);
}

class SelectPage extends StatelessWidget with BaseView<SelectVM> {
  @override
  ViewConfig<SelectVM> initConfig(BuildContext context) =>
      ViewConfig(vm: SelectVM());

  @override
  Widget vmBuild(
      BuildContext context, SelectVM vm, Widget child, Widget state) {
    return Scaffold(
      appBar: AppBar(title: Text("选择")),
      body: ListView(
        children: <Widget>[
          ListTile(
            title: Text("是否加载数据,用来测试状态页和重新加载数据"),
            trailing: ValueListenableBuilder(
              valueListenable: vm.isLoadData,
              builder: (_, value, __) => Switch(
                value: value,
                onChanged: (value) => vm.isLoadData.value = value,
              ),
            ),
          ),
          ListTile(
            title: Text("是否单独配置状态页,用来测试状态页和重新加载数据"),
            trailing: ValueListenableBuilder(
              valueListenable: vm.isConfigState,
              builder: (_, value, __) => Switch(
                value: value,
                onChanged: (value) => vm.isConfigState.value = value,
              ),
            ),
          ),
          ListTile(
            title: Text("根布局刷新"),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => ArticlePage(
                    true,
                    configState: vm.isConfigState.value,
                    loadData: vm.isLoadData.value,
                  ),
                ),
              );
            },
          ),
          ListTile(
            title: Text("根布局不刷新"),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => ArticlePage(
                    false,
                    configState: vm.isConfigState.value,
                    loadData: vm.isLoadData.value,
                  ),
                ),
              );
            },
          ),
        ],
      ),
    );
  }
}

ArticleEntity #

模拟接口返回的数据实体类:

class ArticleEntity extends BaseEntity {
  List<ArticleItem> list;

  ArticleEntity(this.list);
}

class ArticleItem {
  String id;
  String title;
  String content;
  String time;

  ArticleItem(this.id, this.title, this.content, this.time);
}

ArticleVM #

UserModel 继承 BaseModel,ArticleEntity继承BaseEntity,ArticleItem 暂没要求。 是否首次加载数据测试空状态页的效果 创建vnTime 用来监听List第一个ArticleItem的时间刷新


class ArticleVM
    extends BaseListViewModel<UserModel, ArticleEntity, ArticleItem> {
  ArticleVM(this.isLoadData);
  bool isLoadData = true;

  /// 首次加载
  bool firstLoad = true;
  ValueNotifier<String> vnTime = ValueNotifier("暂无");

  @override
  void jointList(ArticleEntity newEntity) => entity.list.addAll(newEntity.list);

  @override
  List<ArticleItem> get list => entity.list;
  @override
  Future<DataResponse<ArticleEntity>> requestHttp(
      {bool isLoad, int page, params}) {
    /// 判断是否加载数据, 测试状态页用
    if (!isLoadData && firstLoad) {
      firstLoad = false;
      return null;
    }
    return model.getArticleList();
  }

  @override
  void initResultData() {
    vnTime.value = list[0].time;
  }

  /// 修改第一个数据的时间
  void modifyFistTime() {
    list[0].time = DateTime.now().toString();
    vnTime.value = list[0].time;
    notifyListeners();
  }
}

ArticlePage View #

文章具体页面,显示一个列表,下方显示第一个item对应的时间,和根布局刷新的时间。

class ArticlePage extends StatelessWidget with BaseView<ArticleVM> {
  const ArticlePage(
    this.rootRefresh, {
    Key key,
    this.configState = false,
    this.loadData = true,
  }) : super(key: key);

  /// 是否全局刷新
  final bool rootRefresh;
  final bool configState;
  final bool loadData;

  @override
  ViewConfig<ArticleVM> initConfig(BuildContext context) {
    var _empty = configState ? (vm) => Center(child: Text("单独配置:empty")) : null;
    return rootRefresh
        ? ViewConfig<ArticleVM>(vm: ArticleVM(loadData), empty: _empty)
        : ViewConfig<ArticleVM>.noRoot(vm: ArticleVM(loadData), empty: _empty);
  }

  @override
  Widget vmBuild(
      BuildContext context, ArticleVM vm, Widget child, Widget state) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(title: Text("文章")),
      bottomNavigationBar: state != null
          ? SizedBox()
          : Container(
              color: Colors.amber,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  MaterialButton(
                    onPressed: vm.modifyFistTime,
                    color: Colors.white,
                    child: Text("修改第一个Item时间,测试全局刷新"),
                  ),
                  ValueListenableBuilder<String>(
                    valueListenable: vm.vnTime,
                    builder: (_, value, __) {
                      return Text("第一个Item时间:$value");
                    },
                  ),
                  Text("根布局刷新时间:${DateTime.now().toString()}"),
                ],
              ),
            ),
      body: state ??
          EasyRefresh(
            controller: vm.refreshController,
            onLoad: vm.loadMore,
            onRefresh: vm.pullRefresh,
            child: ListView.builder(
              itemCount: vm.list.length,
              itemBuilder: (ctx, index) {
                return Selector<ArticleVM, ArticleItem>(
                  selector: (_, aVM) => aVM.list[index],
                  shouldRebuild: (pre, next) => pre == next,
                  builder: (_, ArticleItem value, __) => _item(value),
                );
              },
            ),
          ),
    );
  }

  Widget _item(ArticleItem item) {
    return Container(
      color: Colors.lightGreen,
      margin: EdgeInsets.all(8),
      padding: EdgeInsets.all(4),
      child: Column(
        children: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              Text(item.title),
              Text(item.time),
            ],
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(item.content),
          ),
        ],
      ),
    );
  }
}

数据刷新 #

通过ValueListenableBuilder 监听在ArticleVM创建的ValueNotifier 对象,实现局部刷新。 通过Selector 监听ArticleEntityListArticleItem 的变化

ValueListenableBuilder<String>(
                  valueListenable: vm.vnTime,
                  builder: (_, value, __) {
                    return Text("第一个Item时间:$value");
                  },
                )
Selector<ArticleVM, ArticleItem>(
                  selector: (_, aVM) => aVM.list[index],
                  shouldRebuild: (pre, next) => pre == next,
                  builder: (_, ArticleItem value, __) => _item(value),
                )

更多帮助 #

博客讲解:https://blog.csdn.net/q948182974/article/details/106613565

掘金讲解:https://juejin.im/post/5ee86c9b51882543313a0de7

一个MVVM框架附带简单的demo,会一直更新,希望支持一下.有问题可以反馈QQ 275918180。

1
likes
85
points
201
downloads

Publisher

unverified uploader

Weekly Downloads

Implemented using the MVVM architecture, quickly build projects to help consumers focus only on the business implementation

Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

fast_event_bus, flutter, provider

More

Packages that depend on fast_mvvm