微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Flutter 使用 provider 应用说明问题代码

如何解决Flutter 使用 provider 应用说明问题代码

应用说明

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

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

问题

如何从SubMenu1更新Menu1表单的值? 实际上,当您推送一个页面时,它最终处于MaterialApp 级别,因此无法从Menu1 访问我的通知程序。解决方案是通过 MaterialApp 上面的 Notifier 然后。 但是突然间,我的表单不再在每次调用 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,),)
      )
    );
  }
}

我的BottomNavigationBarNotifier :

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();
  }
}

解决方法

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

  • Menu1 有状态
  • SubMenu1 应该能够读取和更新 Menu1 状态
  • Menu1 调用 SubMenu1 作为“子”屏幕,没有其他路径到 SubMenu1

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

Provider 包有助于将状态与 UI 分开。您可以使用这种方法。你说“但突然间,我的表单不再在每次调用 Menu1 时初始化,而是在应用程序启动时只初始化一次”。当然,Menu1 可以在调用时调用一个方法来初始化 Provider 吗?我为 Provider 方法添加了示例代码。一些简短的说明:

  • 我使用 MultiProvider,尽管我只有一个 ChangeNotifierProvider,但这会让您的代码更易于阅读
  • 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',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'),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'),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);
                  }
                },);
  }
}

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

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.green)
  ];
  void _onItemTap(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: const Text('BottomNavigationBar Example 2'),);
  }
}

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);
              },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: ElevatedButton(
                onPressed: () {
                  if (_formKey.currentState.validate()) {
                    _formKey.currentState.save();
                    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                        content: Text(
                            'Subform text: ' + formData.getEntry('child'))));
                  }
                },);
  }
}

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'),body: Consumer<FormData>(
          builder: (context,_) => 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);
                    }
                  },);
  }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。