Использование Scoped Model для поддержания состояния приложения во флаттере - PullRequest
0 голосов
/ 25 июня 2018

Мне нужна помощь в создании архитектуры для моего приложения. Я использую Flutter и scoped_model для поддержания состояния.

Это приложение, которое имеет логин, отображает новости в одной части приложения, а также показывает фотогалерею среди других. Я хотел бы разделить всю эту вещь на отдельные модели. LoginModel, которая содержит состояние входа (например, имя пользователя, токен, имя и т. Д.). NewsModel, которая содержит новости, полученные из API. GalleryModel для хранения имен фотографий и т. Д. Я не уверен, является ли это наилучшей практикой для поддержания состояния с помощью scoped_model.

Например, что, если текстовое поле зависит от LoginModel и NewsModel? Я не уверен, но я думаю, что невозможно получить состояние из двух отдельных моделей. Кроме того, основная причина, по которой я поддерживаю отдельные состояния удержания моделей, заключается в том, что я не хочу, чтобы часть входа в приложение обновлялась при доставке новостей. Я думаю, что так и происходит, когда я помещаю все состояние в одну модель.

Ответы [ 2 ]

0 голосов
/ 27 декабря 2018

Я хотел бы привести простой пример для 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
0 голосов
/ 28 июня 2018

Библиотека scoped_model предназначена для одновременной работы с несколькими играющими моделями. Это одна из причин того, что ScopedModel и ScopedModelDescendant являются обобщенными и имеют параметр типа. Вы можете определить несколько моделей в верхней части дерева виджетов, используя 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()),
              ),
        ),
      ],
    ),
  ),
)
...