Flutter通过提供商的推送页面访问通知程序



应用程序描述

我的应用程序由3个主页组成,可在我的BottomNavigationBar中访问。当我在菜单之间导航时,我希望每次调用都能初始化我的页面。

在我的Menu1表单中,我可以提交我的表单。这将打开一个带有pushNamed的页面,我们将称之为SubMenu1此页面显示基于表单数据计算的结果。在这个页面上,我可以返回pop,什么也不做,或者我有一个按钮,它必须更新我的某些值​​

问题

如何更新值​​SubMenu1中的Menu1体?事实上,当您推送页面时,它最终会达到MaterialApp级别,因此无法从Menu1访问我的通知程序。解决方案是通过MaterialApp上面的通知程序。但突然间,我的窗体不再每次调用Menu1时初始化,而是在应用程序启动时只初始化一次。。。

代码

在提供的代码中,我放置了上面的通知MaterialApp。因此,我可以访问SubMenu1中的通知程序,并且可以修改值​​Menu1中的字段,但当我从导航栏更改页面并返回值时​​仍然存在,页面尚未初始化。

AppScreen

class AppScreen extends StatelessWidget {
const AppScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<LicenseNotifier>(
create: (_) => LicenseNotifier(),
child: ChangeNotifierProvider<BottomNavigationBarNotifier>( // Here my navigation 
create: (BuildContext context) => BottomNavigationBarNotifier(),
child: ChangeNotifierProvider<Menu1Notifier>( // Here my form Notifier for Menu 1
create: (BuildContext context) => Menu1Notifier(),
child: MaterialApp(
title: AppConfig.APPLICATION_NAME,
debugShowCheckedModeBanner: false,
theme: AppTheme().data,
initialRoute: AppRoutes.HOME,
onGenerateRoute: RoutesClass.generate,
),
)
)
);
}
}

我的底部导航栏通知程序:

class BottomNavigationBarNotifier with ChangeNotifier {
int currentIndex = AppConfig.NAVIGATION_DEFAULT_INDEX;
BottomNavigationBarNotifier();
Future<void> navigationScreenIndex({int index}) async{
currentIndex = index;
notifyListeners();
}
Widget loadScreenWithNavigation()
{
switch (currentIndex)
{
case 0:
return Menu1Screen(title: 'Menu 1');
break;
case 1:
return Menu2Screen(title: 'Menu 2');
break;
case 2:
return Menu3Screen(title: 'Menu 3');
break;
default:
return Menu1Screen(title: 'Menu 1');
break;
}
}
}

我的Menu1Screen的通知程序:

class Menu1Notifier extends FormNotifier {
TextEditingController controllerTest;

Menu1Notifier (){
_initialise();
}
Future _initialise() async{
controllerTest = TextEditingController();
notifyListeners();
}
}

我不确定我是否从上面的代码片段中完全理解你在做什么,但我认为我理解要求:

  • 菜单1有状态
  • SubMenu1应该能够读取和更新Menu1状态
  • Menu1调用SubMenu1作为";"孩子";屏幕,没有其他指向SubMenu1的路径

处理这种简单状态的最简单方法是,Menu1在显示状态时将其状态传递给SubMenu1(作为构造函数参数(,而SubMenu1则直接更新它。我在下面展示了这方面的示例代码。当然,这是两个屏幕之间的紧密耦合,但这似乎是一个紧密耦合的要求。

Provider包用于将状态与UI分离。你可以使用这种方法。你说"但突然间,我的表单不再在每次调用Menu1时初始化,而是在应用程序启动时只初始化一次。当调用提供程序时,Menu1肯定可以调用一个方法来初始化它吗?我添加了提供者方法的示例代码。一些简要说明:

  • 我使用MultiProvider,即使我只有一个ChangeNotificationProvider,这也会让你的代码更容易阅读
  • ChangeNotifier FormData保存表单状态
  • 父窗体初始化窗体状态
  • 两个窗体都调用FormData方法来设置和获取状态

长示例代码直接状态如下:

import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: FormTest(),
),
),
);
}
}
class FormTest extends StatefulWidget {
@override
_FormTestState createState() => _FormTestState();
}
class _FormTestState extends State<FormTest> {
int _selectedIndex = 0;
final List<Widget> _options = [
FormWidget(),
PlaceholderWidget(Colors.deepOrange),
PlaceholderWidget(Colors.green)
];
void _onItemTap(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Example'),
backgroundColor: Colors.teal),
body: Center(
child: _options.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
backgroundColor: Colors.teal),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
backgroundColor: Colors.cyan),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
backgroundColor: Colors.lightBlue,
),
],
type: BottomNavigationBarType.shifting,
currentIndex: _selectedIndex,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.grey,
iconSize: 40,
onTap: _onItemTap,
elevation: 5),
);
}
}
class PlaceholderWidget extends StatelessWidget {
final Color color;
PlaceholderWidget(this.color);
@override
Widget build(BuildContext context) {
return Container(
color: color,
);
}
}
class FormWidget extends StatefulWidget {
@override
FormWidgetState createState() {
return FormWidgetState();
}
}
class FormWidgetState extends State<FormWidget> {
final _formKey = GlobalKey<FormState>();
final _formData = {};
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
onSaved: (value) {
_formData['parent'] = value;
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Parent text: ' + _formData['parent'])));
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SubFormWidget(_formData)),
);
}
},
child: Text('SubForm'),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Subform text: ' + _formData['child'])));
}
},
child: Text('Submit'),
),
),
],
),
);
}
}
class SubFormWidget extends StatefulWidget {
final Map _formData;
SubFormWidget(this._formData);
@override
SubFormWidgetState createState() {
return SubFormWidgetState();
}
}
class SubFormWidgetState extends State<SubFormWidget> {
final _subFormKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Form(
key: _subFormKey,
child: Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Example'),
backgroundColor: Colors.teal),
body: Column(
children: <Widget>[
Text(widget._formData['parent']),
TextFormField(
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
onSaved: (value) {
widget._formData['child'] = value;
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
if (_subFormKey.currentState!.validate()) {
_subFormKey.currentState!.save();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'Subform text: ' + widget._formData['child'])));
Navigator.pop(context);
}
},
child: Text('Submit'),
),
),
],
),
),
);
}
}

提供者方法的长示例代码:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<FormData>(
create: (ctx) => FormData(),
),
],
child: MaterialApp(
title: 'Test App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FormTest2(),
),
);
}
}
class FormTest2 extends StatefulWidget {
FormTest2({Key key}) : super(key: key);
@override
_FormTest2State createState() => _FormTest2State();
}
class _FormTest2State extends State<FormTest2> {
int _selectedIndex = 0;
final List<Widget> _options = [
FormWidget2(),
PlaceholderWidget(Colors.deepOrange),
PlaceholderWidget(Colors.green)
];
void _onItemTap(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Example 2'),
backgroundColor: Colors.teal),
body: Center(
child: _options.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
backgroundColor: Colors.teal),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
backgroundColor: Colors.cyan),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
backgroundColor: Colors.lightBlue,
),
],
type: BottomNavigationBarType.shifting,
currentIndex: _selectedIndex,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.grey,
iconSize: 40,
onTap: _onItemTap,
elevation: 5),
);
}
}
class PlaceholderWidget extends StatelessWidget {
final Color color;
PlaceholderWidget(this.color);
@override
Widget build(BuildContext context) {
return Container(
color: color,
);
}
}
class FormWidget2 extends StatefulWidget {
@override
FormWidget2State createState() {
return FormWidget2State();
}
}
class FormData extends ChangeNotifier {
var _formData = <String, String>{};
void init() {
_formData = <String, String>{};
// No notifyListeners() needed in this use case
}
void setEntry(String key, String value) {
_formData[key] = value;
// notifyListeners() may or may not be needed in this use case
notifyListeners();
}
String getEntry(String key) {
var value = _formData[key];
return value;
}
}
class FormWidget2State extends State<FormWidget2> {
final _formKey = GlobalKey<FormState>();
@override
void initState() {
Provider.of<FormData>(context, listen: false).init();
super.initState();
}
@override
Widget build(BuildContext context) {
return Consumer<FormData>(
builder: (context, formData, _) => Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
initialValue: formData.getEntry('parent'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
onSaved: (value) {
formData.setEntry('parent', value);
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'Parent text: ' + formData.getEntry('parent'))));
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SubFormWidget2()),
);
}
},
child: Text('SubForm'),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'Subform text: ' + formData.getEntry('child'))));
}
},
child: Text('Submit'),
),
),
],
),
),
);
}
}
class SubFormWidget2 extends StatefulWidget {
@override
SubFormWidget2State createState() {
return SubFormWidget2State();
}
}
class SubFormWidget2State extends State<SubFormWidget2> {
final _subFormKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Form(
key: _subFormKey,
child: Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Example 2'),
backgroundColor: Colors.teal),
body: Consumer<FormData>(
builder: (context, formData, _) => Column(
children: <Widget>[
Text(formData.getEntry('parent')),
TextFormField(
initialValue: formData.getEntry('child'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
onSaved: (value) {
formData.setEntry('child', value);
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
if (_subFormKey.currentState.validate()) {
_subFormKey.currentState.save();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'Subform text: ' + formData.getEntry('child'))));
Navigator.pop(context);
}
},
child: Text('Submit'),
),
),
],
),
),
),
);
}
}

最新更新