我有一个应用程序,可以在登录后路由到"main app"页面.此应用程序包含一个底部导航栏,其中显示相应按下的图标的页面.我想将类型为Map<String, dynamic>的数据传递到这些页面,但遇到了问题.此映射由一个函数生成,该函数从服务器获取数据,将其保存到共享首选项,然后加载共享首选项并将其作为映射返回(所有内容都包含在getData()中).我希望传递此映射,这样我就不必每次都加载共享首选项,但也会在需要时随共享首选项一起更新此映射(可能是某个页面上的操作).

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

我收到一个错误,说是Only static members can be accessed in initializers.我想知道继承的小部件或其他设计模式(如作用域模型和块)是否有帮助,但不确定这是不是正确的方法.我也不确定在这种情况下我将如何开始实现它们.

推荐答案

代码中有两个问题:

  1. initState()的正文中使用异步方法 有关详细信息,请参阅here

  2. 在初始值设定项中使用实例数据 有关详细信息,请参阅here

下面是对您的代码进行非常基本的重写,只需最少的修改.

数据 map 从模拟后端加载,在PageOne内部更新,并在PageTwo ONTAP回调中打印到控制台.

请注意,我已将实例变量Data更改为data,以符合Effective Dart条准则.

请注意,要点没有正确解决后端服务与共享首选项的同步问题:这可能是最终产品中必须考虑的问题.

我刚刚 comments 了让您的代码正常工作所需的内容: 如果您的系统的复杂性和与外部API的关系开始增长,那么可能值得考虑块架构.

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

Dart相关问答推荐

为什么 StatefulWidget 的路由创建失败?

Flutter 中的with关键字

AngularDart 可以直接路由到组件吗?

Mockito - 在空安全迁移后存根方法

如何在 Flutter 中更改 Html 小部件中的字体样式?

Flutter 中的嵌套数据和 BLoC

如何垂直对齐行元素?

如何在 Flutter 中管理 Firebase 身份验证状态?

从real mobile浏览器访问Flatter localhost

如何 Select 性地传递可选参数?

dart:web_gl: 渲染警告:texture bound to texture unit 0 is not renderable

谷歌的 Dart 编程语言的作用是什么?

什么是健全的编程语言?

Dart:将map转换为查询字符串

从 Dart Map 中删除选定的键

比较在 Dart 中创建单例的方法

如何在dart中生成随机字符串?

有没有办法在 Dart 中通过引用传递原始参数?

dart 折叠(Fold)与减少(Reduce)

什么是 ?? Dart 中的双问号?