在带有底部导航栏的页面之间传递数据

Dan*_*T29 7 dart flutter

我有一个应用程序,登录后路由到"mainapp"页面.此应用程序包含一个底部导航栏,显示相应的按下图标的页面.我想将类型的数据传递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,
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

我收到一条错误,说只能在初始化程序中访问静态成员.我在想,如果继承部件或其他设计模式,如范围的模型和集团可以帮助,但不知道这是走正道.在这种情况下,我也不确定如何开始实现它们.

att*_*ona 6

您的代码中存在两个问题:

  1. 在主体中使用异步方法,initState() 请参阅此处了解详细信息

  2. 在初始化程序中使用实例数据,请参阅此处了解详细信

以下是对代码进行非常基本的重写,只需进行最少的更正.

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

请注意,我已经改变了实例变量Data,以data使其符合有效飞镖准则.

请注意,要点不能正确解决后端服务与共享首选项的同步问题:这可能会在最终产品中得到解决.

我只是评论它是什么必要让你的代码工作:如果您的系统的复杂性和与外部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) {
    if (index == 0) {
      return PageOne(data:data);
    }
    if (index == 1) {
      return PageTwo(data:data);
    }
    // A fallback, in this case just PageOne
    return PageOne();
  }

  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,
          ),
        ));
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我已经从您的特定代码更新了答案,我希望它更有用. (2认同)
  • 它是正确的:`data`最初是`null`,因为当模拟异步方法`getData`中的`Future`将完成时(1秒后)它将可用.当`getData`返回future将以ready值完成时,传递给`getData.then()`的回调将被调用,其值为:`data`将被更新(并且由于`setState`将重建widget) (2认同)