使用提供程序管理Flutter中的状态

时间:2020-09-29 19:57:27

标签: flutter flutter-provider

我正在尝试在计数器应用程序上实现提供程序状态管理,以更好地了解提供程序的功能。我针对两个不同的文本小部件添加了两个按钮。因此,现在每当我单击两个小部件中的任何一个时,两个文本小部件都会得到更新并赋予相同的值。我希望两个小部件都彼此独立。 我已经使用过ScopedModel并获得了期望的结果,但是现在我想尝试使用provider。

图片链接:https://i.stack.imgur.com/ma3tR.png

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("====Home Page Rebuilt====");
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Container(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        //crossAxisAlignment:CrossAxisAlignment.center,
        children: [
          Consumer<CounterModel>(
            builder: (context, value, child) {
              return CustomWidget(
                number: value.count.toString(),
              );
            },
          ),
          Consumer<CounterModel>(
            builder: (context, value, child) {
              return CustomWidget(
                number: value.count.toString(),
              );
            },
          ),
        ],
      )),
    );
  }
}

class CustomWidget extends StatelessWidget {
  final String number;

  const CustomWidget({Key key, this.number}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    print("====Number Page Rebuilt====");
    return ButtonBar(
      alignment: MainAxisAlignment.center,
      children: [
        Consumer<CounterModel>(
          builder: (context, value, child) {
            return Text(
              value.count.toString(),
              style: Theme.of(context).textTheme.headline3,
            );
          },
        ),
        FlatButton(
          color: Colors.blue,
          onPressed: () =>
              Provider.of<CounterModel>(context, listen: false).increment(),
          child: Text("Click"),
        ),
      ],
    );
  }
}


 

1 个答案:

答案 0 :(得分:0)

如果您希望它们彼此独立,则需要以某种方式区分它们。我在实现提供程序方面有一些不同的风格,它并没有让我失望。这是一个完整的示例。

您应该将实现修改为类似以下内容:

在CounterProvider.dart文件中定义扩展ChangeNotifier的提供程序类

import 'package:flutter/material.dart';

class CounterProvider extends ChangeNotifier {
  /// You can either set an initial value here or use a UserProvider object
  /// and call the setter to give it an initial value somewhere in your app, like in main.dart

  int _counter = 0; // This will set the initial value of the counter to 0

  int get counter => _counter;

  set counter(int newValue) {
    _counter = newValue;

    /// MAKE SURE YOU NOTIFY LISTENERS IN YOUR SETTER
    notifyListeners();
  }
}

像这样用Provider Widget包装您的应用

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
/// don't forget to import it here too
import 'package:app/CounterProvider.dart';


void main() {
  runApp(
    MaterialApp(
      initialRoute: '/root',
      routes: {
        '/root': (context) => MyApp(),
      },
      title: "Your App Title",
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        /// Makes data available to everything below it in the Widget tree
        /// Basically the entire app.
        ChangeNotifierProvider<CounterProvider>.value(value: CounterProvider()),
      ],
      child: MaterialApp(
        home: HomeScreen(),
      ),
    );
  }
}

在应用程序中的任何位置访问和更新数据

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
/// MAKE SURE TO IMPORT THE CounterProvider.dart file
import 'package:app/CounterProvider.dart';

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  CounterProvider counterProvider;

  @override
  Widget build(BuildContext context) {
    /// LISTEN TO THE CHANGES / UPDATES IN THE PROVIDER
    counterProvider = Provider.of<CounterProvider>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Container(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          //crossAxisAlignment:CrossAxisAlignment.center,
          children: [
            _showCounterButton(1),
            _showCounterButton(2),
          ],
        ),
      ),
    );
  }

  Widget _showCounterButton(int i) {
    return ButtonBar(
      alignment: MainAxisAlignment.center,
      children: [
        Text(
          i == 1
              ? counterProvider.counter1.toString()
              : counterProvider.counter2.toString(),
          style: Theme.of(context).textTheme.headline3,
        ),
        FlatButton(
          color: Colors.blue,
          onPressed: () {
            /// UPDATE DATA IN THE PROVIDER. BECAUSE YOU're USING THE SETTER HERE,
            /// THE LISTENERS WILL BE NOTIFIED AND UPDATE ACCORDINGLY
            /// you can do this in any other file anywhere in the Widget tree, as long as
            /// it it beneath the main.dart file where you defined the MultiProvider
            i == 1
                ? counterProvider.counter1 += 1
                : counterProvider.counter2 += 1;
            setState(() {});
          },
          child: Text("Click"),
        ),
      ],
    );
  }
}

如果需要,可以稍微更改实现。如果您有多个计数器,则对于多个窗口小部件,只需在CounterProvider.dart文件中创建更多变量,并为每个计数器分别设置setter和getter。然后,要正确显示/更新它们,只需在_showCounterButton()方法内部和onPressed: (){ switch case here, before setState((){}); }内部使用开关盒即可。

希望这会有所帮助,并使您更好地了解Provider的工作方式。