如何更改 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
来刷新小部件(而不是使用 ChangeNotifierProvider
和 Consumer
以“监听”和“本地化”小部件重建到 Switch
和 Text
标签,这可能是更典型的用法):
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,
)
],
),
),
),
),
);
}
}
我在屏幕上有一个 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
来刷新小部件(而不是使用 ChangeNotifierProvider
和 Consumer
以“监听”和“本地化”小部件重建到 Switch
和 Text
标签,这可能是更典型的用法):
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,
)
],
),
),
),
),
);
}
}