dart - 在 flutter 中使用底部导航栏在页面之间传递数据

我有一个应用程序在登录后会路由到“mainapp”页面。这个应用程序包含一个底部导航栏,显示相应按下图标的页面。我想传递 Map<String, dynamic> 类型的数据到这些页面,但我遇到了麻烦。该映射由一个函数生成,该函数从服务器获取数据,将其保存到共享首选项,然后加载共享首选项并将其作为映射返回(全部包含在 getData() 中)。我想传递这张 map ,这样我就不必每次都加载共享偏好,但也会在需要时更新这张 map 以及共享偏好(可能是其中一个页面上的操作)。

class MainApp extends StatefulWidget {
  @override
  _MainAppState createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {


  Map<String, dynamic> Data;


  StartFunc() async {
   Data = await getData();
   setState(() {}); 
 }


  @override
  void initState() {
    StartFunc();
    super.initState();
  }

  var _pages = [
    PageOne(Data:Data),
    PageTwo(),
    PageThree(),
   PageFour(),
   PageFive(),
  ];

  int _currentIndex = 0;

  onTabTapped(int index) {
    setState(() {
      _currentIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return _currentIndex == 2
        ? PageTwo()
        : Scaffold(
      body: _pages[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        items: [
          BottomNavigationBarItem(
              icon: Icon(Icons.library_books), title: Text('')),
          BottomNavigationBarItem(
              icon: Icon(Icons.notifications), title: Text('')),
          BottomNavigationBarItem(
              icon: Icon(Icons.add_circle_outline), title: Text('')),
          BottomNavigationBarItem(
              icon: Icon(Icons.mail), title: Text('')),
          BottomNavigationBarItem(
              icon: Icon(Icons.person), title: Text('')),
        ],
        onTap: onTabTapped,
        currentIndex: _currentIndex,
      ),
    );
  }
}

我收到一条错误消息,提示 在初始化程序中只能访问静态成员。我想知道继承的小部件或其他设计模式(例如范围模型和 BLoC)是否可以提供帮助,但不确定这是否是正确的方法。我也不确定在这种情况下我将如何开始实现它们。

最佳答案

你的代码有两个问题:

  1. initState() 的主体中使用异步方法 见 here了解详情

  2. 在初始化器中使用实例数据 见 here了解详情

接下来是对您的代码进行非常基本的重写,并进行了最少的修正。

数据映射从模拟后端加载,在 PageOne 内部更新,并在 PageTwo onTap 回调中打印到控制台。

请注意,我已将实例变量 Data 更改为 data 以符合 Effective Dart指导方针。

请注意,要点没有正确解决后端服务与共享偏好的同步问题:这可能必须在最终产品中加以考虑。

我刚刚评论了使您的代码正常工作所必需的内容: 如果您的系统的复杂性以及与外部 API 的关系开始增长,那么可能值得考虑使用 Bloc 架构。

import 'package:flutter/material.dart';

void main() => runApp(new MainApp());

// Mock up of an async backend service
Future<Map<String, dynamic>> getData() async {
  return Future.delayed(Duration(seconds: 1), () => {'prop1': 'value1'});
}

class PageOne extends StatelessWidget {
  final Map<String, dynamic> data;

  PageOne({Key key, this.data}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        child: const Text('update preferences'),
        onPressed: () {
          data['prop2'] = 'value2';
        },
      ),
    );
  }
}

class PageTwo extends StatelessWidget {

  final Map<String, dynamic> data;

  PageTwo({Key key, this.data}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        child: const Text('Got It!'),
        onPressed: () {
          print("data is now: [$data]");
        },
      ),
    );
  }
}

class MainApp extends StatefulWidget {
  @override
  _MainAppState createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  //Map<String, dynamic> Data;
  Map<String, dynamic> data;

  /*
  StartFunc() async {
    Data = await getData();
    setState(() {});
  }
  */

  @override
  void initState() {
    //StartFunc();
    super.initState();
    getData().then((values) {
      setState(() {
        data = values;
      });
    });
  }

  /*
  PageOne(data:data) is an invalid value for an initializer:
   there is no way to access this at this point.
    Initializers are executed before the constructor,
    but this is only allowed to be accessed after the call
    to the super constructor.

  */
  /*
  var _pages = [
    PageOne(data:data),
    PageTwo(),
  ];
  */

 Widget getPage(int index) {
    switch (index){
        case 0:
            return PageOne(data:data);
            break;
        case 1:
            return PageTwo(data:data);
            break;
        default:
            return PageOne();
        break;
    }
  }

  int _currentIndex = 0;

  onTabTapped(int index) {
    setState(() {
      _currentIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    /*
    return _currentIndex == 2
        ? PageTwo()
        : Scaffold(

    I use a MaterialApp because of material widgets (RaisedButton)
    It is not mandatory, but it is mainstream in flutter

     */
    return MaterialApp(
        title: 'My App',
        home: Scaffold(
          appBar: AppBar(title: Text("My App Bar")),
          body: getPage(_currentIndex),
          bottomNavigationBar: BottomNavigationBar(
            type: BottomNavigationBarType.fixed,
            items: [
              BottomNavigationBarItem(
                  icon: Icon(Icons.first_page), title: Text('')),
              BottomNavigationBarItem(
                  icon: Icon(Icons.last_page), title: Text('')),
            ],
            onTap: onTabTapped,
            currentIndex: _currentIndex,
          ),
        ));
  }
}

https://stackoverflow.com/questions/54251317/

相关文章:

flutter - 如何在 Flutter 中使用音频播放器插件播放本地 mp3 文件

flutter - 展开 Flutter 中的应用栏以允许多行标题?

dart - Flutter:如何获取文本行数

dart - 如何在 Flutter 中添加文件选择器插件?

visual-studio - 是否可以在 Visual Studio 2017 IDE 上设置 f

flutter - 像 SliverAppBar 一样隐藏 TabBar

date - 如何在 flutter 中创建计时器选择器?

firebase - 如何通过与 Flutter Cloud Firestore 插件中的日期进行比

android - Flutter 检索 ro.product.cpu.abi 的设备属性时出错

dart - pubspec.yaml 中的配置标志如何工作?