Flutter 如何使用共享首选项读取颤振中所有底部选项卡屏幕的数据

Flutter 如何使用共享首选项读取颤振中所有底部选项卡屏幕的数据,flutter,navigation,Flutter,Navigation,我需要保存数据,然后在所有选项卡中读取数据,并尝试使用共享首选项保存和读取数据。现在我有3个屏幕,它们是登录、主页和配置文件屏幕。在home和profile中,我使用底部选项卡导航器,所以在用户登录后(发布他们的数据,我使用共享首选项保存数据,我希望在home和profile屏幕中访问这些数据)。让我困惑的是。。。单击“登录”按钮后,我将其导航到底部选项卡文件,其中按钮选项卡文件由主屏幕和配置文件屏幕组成,我不知道如何使用共享首选项读取主屏幕和配置文件屏幕中的数据,因为登录后,我将其导航到底部选

我需要保存数据,然后在所有选项卡中读取数据,并尝试使用共享首选项保存和读取数据。现在我有3个屏幕,它们是登录、主页和配置文件屏幕。在home和profile中,我使用底部选项卡导航器,所以在用户登录后(发布他们的数据,我使用共享首选项保存数据,我希望在home和profile屏幕中访问这些数据)。让我困惑的是。。。单击“登录”按钮后,我将其导航到底部选项卡文件,其中按钮选项卡文件由主屏幕和配置文件屏幕组成,我不知道如何使用共享首选项读取主屏幕和配置文件屏幕中的数据,因为登录后,我将其导航到底部选项卡,而不是主屏幕。这是我的密码 主飞镖

void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: LoginScreen(),
    );
  }
}
我的登录屏幕

class _LoginScreenState extends State<LoginScreen> {
postData() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  prefs.setInt('username', _username.text);
  Navigator.push(context,
              new MaterialPageRoute(
                  builder: (BuildContext context) =>
                      new BottomTab()));
}
@override
  Widget build(BuildContext context) {
    return Column(
             children:<Widget>[
               TextFormField(
                 controller: _username),
               FlatButton(
                 child: Text("Login"),
                 onPressed: () {
                    postData(_username.text);}),];}
}
class\u LoginScreenState扩展状态{
postData()异步{
SharedReferences prefs=等待SharedReferences.getInstance();
prefs.setInt('username',_username.text);
Navigator.push(上下文,
新材料路线(
生成器:(BuildContext上下文)=>
新的底部选项卡());
}
@凌驾
小部件构建(构建上下文){
返回列(
儿童:[
TextFormField(
控制器:_用户名),
扁平按钮(
子项:文本(“登录”),
已按下:(){
postData(_username.text);}),];}
}
我的底部标签文件

class _BottomTab extends State<BottomTab> {

  int _selectedIndex = 0;

  _onTap(int index) {
    setState(() => _myindex = index);
  }

  final List<Widget> pages = [
    HomeScreen(),
    ProfileScreen(), 
  ];

  final PageStorageBucket bucket = PageStorageBucket();

  Widget _myNavigation(int selectedIndex) => BottomNavigationBar(
        onTap: _onTap,
        currentIndex: myindex,
        type: BottomNavigationBarType.fixed,
        items: const <MyTab>[
          MyTab(icon: Icon(Icons.home), title: Text('Home')),
          MyTab(icon: Icon(Icons.person), title: Text('Profile')),
        ],
      );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: _myNavigation(_myindex),
      body: PageStorage(
        child: pages[_myindex],
        bucket: bucket,
      ),
    );
  }
}
class\u BottomTab扩展状态{
int _selectedIndex=0;
_onTap(整数索引){
设置状态(()=>_myindex=index);
}
最终列表页=[
主屏幕(),
ProfileScreen(),
];
final PageStorageBucket bucket=PageStorageBucket();
小部件_myNavigation(int-selectedIndex)=>BottomNavigationBar(
onTap:_onTap,
当前索引:myindex,
类型:BottomNavigationBarType.fixed,
项目:常数[
MyTab(图标:图标(Icons.home),标题:文本(“home”),
MyTab(图标:图标(Icons.person),标题:文本('Profile'),
],
);
@凌驾
小部件构建(构建上下文){
返回脚手架(
底部导航栏:_myNavigation(_myindex),
正文:页面存储(
子:页面[_myindex],
桶:桶,
),
);
}
}
我的主屏幕

class _HomeScreen extends State<HomeScreen> {
@override
  Widget build(BuildContext context) {

    return Container(
      child: Text("Hello ${...username that I want to pass}"),
    );
  }
}

class\u主屏幕扩展状态{
@凌驾
小部件构建(构建上下文){
返回容器(
child:Text(“Hello${…我要传递的用户名}”),
);
}
}

您可以在任何地方提取应用程序中的SharedReferences。正如您所说,您还必须访问HomePage和ProfilePage中的SharedReferences数据。因此,您现在有两个选项:

  • 您可以在底部选项卡页面中提取共享首选项,并将其传递到HomePage和ProfilePage
  • 此外,您还可以分别提取这两个页面中的SharedReference
  • 要提取SharedReference,可以参考以下代码:

    SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
    var userName = sharedPrefs.getInt("username")
    

    你可以随时随地提取应用程序中的SharedReferences。正如你所说,你还必须访问HomePage和ProfilePage中的SharedReferences数据。因此,你现在有两个选项:

  • 您可以在底部选项卡页面中提取共享首选项,并将其传递到HomePage和ProfilePage
  • 此外,您还可以分别提取这两个页面中的SharedReference
  • 要提取SharedReference,可以参考以下代码:

    SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
    var userName = sharedPrefs.getInt("username")
    

    您可以选择,每次要显示来自异步源的数据时,都可以使用
    FutureBuilder

    FutureBuilder:

    class _HomeScreen extends State<HomeScreen> {
      Future<int> _getUsername;
    
      @override
      void initState() {
        _getUsername = SharedPreferences.getInstance().then((prefs) { 
           return prefs.getInt("username");
        }
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return FutureBuilder() {
        future: _getUsername,
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.connectionState != ConnectionState.done) {
            // The value is not read yet
            return Text("Loading username...");
          }
    
          final username = snapshot.data.toString();
    
          return Container(
            child: Text("Hello $username"),
          );
        }
      }
    }
    

    您可以选择,每次要显示来自异步源的数据时,都可以使用
    FutureBuilder

    FutureBuilder:

    class _HomeScreen extends State<HomeScreen> {
      Future<int> _getUsername;
    
      @override
      void initState() {
        _getUsername = SharedPreferences.getInstance().then((prefs) { 
           return prefs.getInt("username");
        }
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return FutureBuilder() {
        future: _getUsername,
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.connectionState != ConnectionState.done) {
            // The value is not read yet
            return Text("Loading username...");
          }
    
          final username = snapshot.data.toString();
    
          return Container(
            child: Text("Hello $username"),
          );
        }
      }
    }
    

    但是,当我单击登录按钮时,我是否需要在底部选项卡中传递用户名?我的意思是,我是否应该在此处传递用户名?
    Navigator.push(上下文,new MaterialPageRoute(builder:(BuildContext context)=>new BottomTab(…用户名值(?))
    No,这些共享引用本质上是全局的。您可以在整个应用程序中访问这些引用,而无需传递它。但是,当我单击“登录”按钮时,我是否需要在底部选项卡中传递用户名?我的意思是,我是否应该在此处传递用户名?
    Navigator.push(上下文,new MaterialPageRoute(builder:(BuildContext上下文)=>新的底部选项卡(…用户名值(?))
    不,这些共享引用本质上是全局的。您可以在整个应用程序中访问这些引用,而无需传递。我使用FutureBuilder尝试了第一个选择,但我在屏幕上看到了加载用户名…,这是否意味着用户名没有在共享首选项中设置?您确定没有出错吗?应该可以。您将有“Hello null”没有用户名。如果在内部,请检查Conditionalbuilder@uyhaW尝试在postData方法中为setInt添加
    wait
    。我认为您读取值太早。此条件是强制性的,因为您必须在尚未加载数据时返回一个小部件。但是如果您希望避免每次在
    主屏幕
    实例,您必须由父级加载数据。第二种解决方案会更好。当然,您也可以将
    FutureBuilder
    放在
    BottomTab
    中,并将数据传递到
    主屏幕
    constructor@uyhaW我用第三种解决方案编辑了我的文章。这就足够了。但是如果你想传递数据,请点击thr通过该树,提供程序将比向每个构造函数传递数据更简单。我使用FutureBuilder尝试了第一种选择,但我的屏幕中出现了
    加载用户名…
    ,这是否意味着用户名没有在共享首选项中设置?你确定没有出错吗?应该可以。你将有“Hello null”没有用户名。如果在内部,请检查Conditional
    class _BottomTab extends State<BottomTab> {
    // ....
    
      @override
      Widget build(BuildContext context) {
        return FutureBuilder() {
          future: _getUsername,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if (snapshot.connectionState != ConnectionState.done) {
              // The value is not read yet
              return Text("Loading username...");
            }
    
            return HomeScreen(snapshot.data.toString());
        }
      }
    }