简体   繁体   English

如何更改 Stateful Widget 中 Switch 的 state,从 Provider 检索数据?

[英]How to change the state of a Switch in a Stateful Widget, retrieving data from a Provider?

I have a Switch on a screen and I need it to use the value that is in a Provider.我在屏幕上有一个 Switch,我需要它来使用 Provider 中的值。 I've tried to infer this value using the provider's value, but the Switch is immobile, it doesn't change visually(but the value is changed in the DB), it only works as it should when I remove the provider's inferences.我尝试使用提供者的值来推断这个值,但是 Switch 是不动的,它不会在视觉上发生变化(但是数据库中的值会发生变化),它只有在我删除提供者的推论时才能正常工作。

My Provider: (It is being called when I start the application)我的提供者:(当我启动应用程序时它被调用)

class DailyDatabase with ChangeNotifier {
  
  bool notificationActive = false;

void loadDailyData() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    notificationActive = prefs.getBool('notificationActive') ?? false;}

Variable:多变的:

@override
  Widget build(BuildContext context) {
    final provider = Provider.of<DailyDatabase>(context);
    _notificationActive = provider.notificationActive;

Switch:转变:

Switch(
          value: _notificationActive,
          onChanged: (value) {
            _notificationActive = value;
            provider.setNotification(value);
          },
        ),

You have to add setState((){});您必须添加setState((){}); which rebuild the screen and display changes on your screen重建屏幕并在屏幕上显示更改

Stateful Version - Provider only有状态版本 - 仅提供者

Here's a very basic example of Provider with a Switch and using StatefulWidget and its setState to refresh the widget (instead of using ChangeNotifierProvider and Consumer to "listen" and "localize" the widget rebuild to just the Switch and the Text label, which is perhaps a more typical use):这是一个非常基本的带有SwitchProvider示例并使用StatefulWidget及其setState来刷新小部件(而不是使用ChangeNotifierProviderConsumer来“侦听”和“本地化”小部件重建为SwitchText label,这可能是更典型的用法):

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

class SwitchProviderPage extends StatefulWidget {
  @override
  _SwitchProviderPageState createState() => _SwitchProviderPageState();
}

class Database {
  bool active = false;

  void setActive(bool value) {
    active = value;
  }
}

class _SwitchProviderPageState extends State<SwitchProviderPage> {
  @override
  Widget build(BuildContext context) {
    return Provider(
        create: (context) => Database(),
      child: Builder(
        builder: (context) {
          Database db = Provider.of<Database>(context, listen: false);
          return Scaffold(
            appBar: AppBar(
              title: Text('Switch Field'),
            ),
            body: SafeArea(
              child: Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text('Active? ${db.active}'),
                    Switch(
                      onChanged: (val) { // ← remember to use val (bool)
                        print('Switch value: $val');
                        setState(() {
                          db.setActive(val);
                          // this sets the Switch setting on/off
                        });

                      },
                      value: db.active,
                    )
                  ],
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

Note :注意

The use of Builder in above is only to make Scaffold be a child of Provider .上面使用Builder只是为了让Scaffold成为Provider的子级。 Otherwise, Scaffold would be a sibling, not a child, and Provider will not work.否则, Scaffold将是兄弟姐妹,而不是孩子,并且Provider将无法工作。 Since you wrap your entire app in your ChangeNotifierProvider , you don't need to do this.由于您将整个应用程序包装在ChangeNotifierProvider中,因此您不需要这样做。 I needed to do this to get a self-contained example.我需要这样做以获得一个独立的示例。

Stateless Version - ChangeNotifierProvider + Consumer无状态版本 - ChangeNotifierProvider + Consumer

Here's a complete app example (copy paste into main.dart, replacing everything on page) using a StatelessWidget and the typical/common ChangeNotifierProvider & Consumer .这是一个完整的应用示例(将粘贴复制到 main.dart,替换页面上的所有内容)使用StatelessWidget和典型/常见的ChangeNotifierProviderConsumer

This version uses a mocked long duration async call when flipping Switch .此版本在翻转Switch时使用模拟的长时间异步调用。

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

void main() {
  runApp(ChangeNotifierProvider<DatabaseListenable>(
      create: (context) => DatabaseListenable(),
      child: MyApp())
  );
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Provider Demo App',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: StatelessSwitchProviderPage(),
    );
  }
}

class DatabaseListenable with ChangeNotifier {
  bool active = false;

  Future<void> setActive(bool value) async {
    // Mock slow database call ↓
    await Future.delayed(Duration(milliseconds: 500), () {
      active = value;
      print('Async DB call DONE.');
    });
    notifyListeners(); // ← causes Consumer to rebuild
  }
}

class StatelessSwitchProviderPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Switch Provider Stateless'),
      ),
      body: SafeArea(
        child: Center(
          child: Consumer<DatabaseListenable>(
            builder: (context, db, child) =>  Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('Active? ${db.active}'),
                Switch(
                  onChanged: (val) {
                    print('Switch value: $val');
                    db.setActive(val);
                  },
                  value: db.active,
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM