使用作用域模型来维持应用状态

时间:2018-06-25 08:44:15

标签: flutter scoped-model

我需要为我的应用程序创建体系结构的帮助。我正在使用Flutter和 scoped_model 来维持状态。

这是一个具有登录名的应用程序,它在该应用程序的一部分中显示新闻,并在其中显示照片库。我想将整个过程分解为单独的模型。拥有登录状态(例如用户名,令牌,名称等)的LoginModel。包含从API检索的新闻的NewsModel。 GalleryModel用来保存照片等的名称。我不确定这是否是使用scoped_model维护状态的最佳实践。

例如,如果文本框同时依赖LoginModel和NewsModel怎么办?我不确定,但是我想不可能从两个单独的模型中检索状态。 另外,我维护单独的模型以保持状态的主要原因是,我不希望在收到新闻时刷新应用程序的“登录”部分。我想将整个状态放在一个模型中就是这样。

2 个答案:

答案 0 :(得分:10)

scoped_model库旨在与多个模型同时运行。这是ScopedModelScopedModelDescendant是泛型且具有类型参数的部分原因。您可以使用ScopedModel<LoginModel>ScopedModel<NewsModel>在小部件树顶部附近定义多个模型,然后使用ScopedModelDescendant<LoginModel>ScopedModelDescendant<NewsModel>在树中较低的位置使用这些模型。后代将根据他们的类型参数去寻找合适的模型。

我整理了一个简单的例子。这是模型:

class ModelA extends Model {
  int count = 1;
  void inc() {
    count++;
    notifyListeners();
  }
}

class ModelB extends Model {
  int count = 1;
  void inc() {
    count++;
    notifyListeners();
  }
}

这是我在应用程序中显示的内容:

ScopedModel<ModelA>(
  model: ModelA(),
  child: ScopedModel<ModelB>(
    model: ModelB(),
    child: ScopedModelDescendant<ModelA>(
      builder: (_, __, a) => ScopedModelDescendant<ModelB>(
        builder: (_, __, b) {
          return Center(
            child: Column(
              children: [
                GestureDetector(
                  onTap: () => a.inc(),
                  child: Text(a.count.toString()),
                ),
                SizedBox(height:100.0),
                GestureDetector(
                  onTap: () => b.inc(),
                  child: Text(b.count.toString()),
                ),
              ],
            ),
          );
        },
      ),
    ),
  ),
)

似乎工作正常。一种非嵌套的方法也可以:

ScopedModel<ModelA>(
  model: ModelA(),
  child: ScopedModel<ModelB>(
    model: ModelB(),
    child: Column(
      children: [
        ScopedModelDescendant<ModelA>(
          builder: (_, __, model) => GestureDetector(
                onTap: () => model.inc(),
                child: Text(model.count.toString()),
              ),
        ),
        SizedBox(height: 100.0),
        ScopedModelDescendant<ModelB>(
          builder: (_, __, model) => GestureDetector(
                onTap: () => model.inc(),
                child: Text(model.count.toString()),
              ),
        ),
      ],
    ),
  ),
)

答案 1 :(得分:5)

我想给你一个关于ScopedModel的简单例子。

pubspec.yaml文件必须包含:-

dependencies:
  scoped_model: ^1.0.1

然后

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

void main() => runApp(MyApp());   //main method

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(), //new class MyHomePage
    );
  }
}

//-----------------------------------CounterModel [used by ScopedModel]
class CounterModel extends Model {
  int _counter = 0;
  int get counter => _counter;
  void increment() {
    _counter++;
    notifyListeners();
  }
}
//-----------------------------------ends


//-----------------------------------MyHomePage class
class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return ScopedModel(    // ScopedModel used on top of the widget tree [it is wrapping up scaffold]
      model: CounterModel(), // providing the CounterModel class as model
      child: Scaffold(
        appBar: AppBar(),
        body: Container(
          child: ScopedModelDescendant<CounterModel>(  // ScopedModelDescendant accessing the data through ScopedModel
            builder: (context, _, model) => Text("${model._counter}"), // fetching data from model without thinking of managing any state.
          ),
        ),
        floatingActionButton: ScopedModelDescendant<CounterModel>(
          builder: (context, _, model) => FloatingActionButton(
                onPressed: model.increment, // calling function of model to increment counter
              ),
        ),
      ),
    );
  }
}
//-----------------------------------ends