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

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

我在屏幕上有一个 Switch,我需要它来使用 Provider 中的值。

我的提供商:(在我启动应用程序时被调用)

class DailyDatabase with ChangeNotifier {
  
  bool notificationActive = false;

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

变量:

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

切换:

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

您必须添加 setState((){}); 重建屏幕并在屏幕上显示更改

有状态版本 - 仅限提供商

这是一个非常基本的 Provider 示例,带有 Switch 并使用 StatefulWidget 及其 setState 来刷新小部件(而不是使用 ChangeNotifierProviderConsumer 以“监听”和“本地化”小部件重建到 SwitchText 标签,这可能是更典型的用法):

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,
                    )
                  ],
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

:

上面使用Builder只是为了让Scaffold成为Provider的child。 否则,Scaffold 将是兄弟,而不是 child,并且 Provider 将不起作用。由于您将整个应用程序包装在 ChangeNotifierProvider 中,因此您不需要这样做。我需要这样做才能获得 self-contained 示例。

无状态版本 - ChangeNotifierProvider + 消费者

这是一个完整的应用程序示例(复制粘贴到 main.dart,替换页面上的所有内容)使用 StatelessWidget 和 typical/common ChangeNotifierProvider & Consumer .

此版本在翻转时使用模拟的长时间异步调用 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,
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}