搜索插件、代码仓与 APP 分类

插件详情v2.0.0

scoped_model

将响应式模型传递给其所有子项的 Widget

AndroidiOSWebmacOSWindowsLinux
近 30 天下载
58.2万
喜欢数
285
Pub 分数
150

安装插件

flutter pub add scoped_model

插件介绍

基于插件公开信息、社区数据与项目使用情况整理的选型参考。

Scoped Model 是一个轻量级的 Flutter 状态管理解决方案,可在小部件树中实现响应式模型共享。它提供了一种简单的方法,将模型对象向下传递到小部件层次结构中,使子小部件能够响应式地访问和更新模型。该包采用作用域方法,确保只有相关的小部件在模型更改时重建,从而提高性能。对于中小型应用来说,它非常理想,因为像 Provider 或 Bloc 这样的完整状态管理解决方案可能过于复杂。支持所有主要平台,可无缝集成到现有的 Flutter 项目中。

适合场景

  • 小型应用中的简单状态管理
  • 在多个小部件之间共享数据
  • 基于模型更改的响应式 UI 更新
  • 管理表单状态
  • 实现主题或用户偏好

主要特点

  • 响应式模型传播
  • 最小化样板代码
  • 跨平台支持
  • 与现有代码的轻松集成
  • 模型更改时自动重建部件

适合对象

  • 初学者 Flutter 开发者
  • 轻量级状态需求
  • Prototyping
  • 中等状态复杂度的应用程序
  • 避免使用重型状态管理框架的项目

使用建议

  • 不适合大规模应用
  • 有限的内置调试工具
  • 不如Riverpod等高级解决方案灵活
  • 手动处理复杂的状态转换
  • 模型更新无内置错误处理

原始 README

以下为关联源码仓库的 README 原文快照,最新内容请访问源码仓库。

scoped_model

Build Status codecov

A set of utilities that allow you to easily pass a data Model from a parent Widget down to its descendants. In addition, it also rebuilds all of the children that use the model when the model is updated. This library was originally extracted from the Fuchsia codebase.

This Library provides three main classes:

  • The Model class. You will extend this class to create your own Models, such as SearchModel or UserModel. You can listen to Models for changes!
  • The ScopedModel Widget. If you need to pass a Model deep down your Widget hierarchy, you can wrap your Model in a ScopedModel Widget. This will make the Model available to all descendant Widgets.
  • The ScopedModelDescendant Widget. Use this Widget to find the appropriate ScopedModel in the Widget tree. It will automatically rebuild whenever the Model notifies that change has taken place.

This library is built upon several features of Flutter:

  • The Model class implements the Listenable interface
    • AnimationController and TextEditingController are also Listenables
  • The Model is passed down the Widget tree using an InheritedWidget. When an InheritedWidget is rebuilt, it will surgically rebuild all of the Widgets that depend on its data. No need to manage subscriptions!
  • It uses the AnimatedBuilder Widget under the hood to listen to the Model and rebuild the InheritedWidget when the model changes.

Examples

  • Counter App - Introduction to the tools provided by Scoped Model.
  • Todo App - Shows how to write a Todo app with persistence and tests.

Usage

Let's demo the basic usage with the all-time favorite: A counter example!

// Start by creating a class that holds some view the app's state. In
// our example, we'll have a simple counter that starts at 0 can be 
// incremented.
//
// Note: It must extend from Model.  
class CounterModel extends Model {
  int _counter = 0;

  int get counter => _counter;

  void increment() {
    // First, increment the counter
    _counter++;
    
    // Then notify all the listeners.
    notifyListeners();
  }
}

// Create our App, which will provide the `CounterModel` to 
// all children that require it! 
class CounterApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // First, create a `ScopedModel` widget. This will provide 
    // the `model` to the children that request it. 
    return new ScopedModel<CounterModel>(
      model: new CounterModel(),
      child: new Column(children: [
        // Create a ScopedModelDescendant. This widget will get the
        // CounterModel from the nearest ScopedModel<CounterModel>. 
        // It will hand that model to our builder method, and rebuild 
        // any time the CounterModel changes (i.e. after we 
        // `notifyListeners` in the Model). 
        new ScopedModelDescendant<CounterModel>(
          builder: (context, child, model) => new Text('${model.counter}'),
        ),
        new Text("Another widget that doesn't depend on the CounterModel")
      ])
    );
  }
}

Finding the Model

There are two ways to find the Model provided by the ScopedModel Widget.

  1. Use the ScopedModelDescendant Widget. It will find the Model and run the builder function whenever the Model notifies the listeners.
  2. Use the ScopedModel.of static method directly. To make this method more readable for frequent access, you can consider adding your own of method to your own Model classes like so:
class CounterModel extends Model {
  // ...
 
  /// Wraps [ScopedModel.of] for this [Model].
  static CounterModel of(BuildContext context) =>
      ScopedModel.of<CounterModel>(context);
}

Listening to multiple Models in a build function

In many cases, it makes sense to split your Models apart into logical components by functionality. For example, rather than having an AppModel that contains all of your application logic, it can often make more sense to split models apart into a UserModel, a SearchModel and a ProductModel, for example.

However, if you need to display information from two of these models in a single Widget, you might be wondering how to achieve that! To do so, you have two options:

  1. Use multiple ScopedModelDescendant Widgets
  2. Use multiple ScopedModel.of calls. No need to manage subscriptions, Flutter takes care of all of that through the magic of InheritedWidgets.
class CombinedWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final username =
      ScopedModel.of<UserModel>(context, rebuildOnChange: true).username;
    final counter =
      ScopedModel.of<CounterModel>(context, rebuildOnChange: true).counter;

    return Text('$username tapped the button $counter times');
  }
}

Contributors

所属分类

源码仓库

使用此插件的项目