firebase - Flutter:即使在屏幕之间导航后也会保存页面的状态

标签 firebase flutter google-cloud-firestore navigation state-management

我有一个简单的目标要实现。我的应用程序中有 2 个屏幕,在主屏幕上有一个按钮,可以将我导航到一个名为“兴趣”的新页面。兴趣页面是一个复选框列表(我只能使用 listview.builder)和一个提交数据的按钮(将我导航回主屏幕)。我想要实现的目标是:

  1. 复选框应该可以正常工作。
  2. 当我从“兴趣”页面导航到主页并再次导航回“兴趣”页面时,所选的复选框应保持选中状态。简而言之,应该保存页面的状态。
  3. 我编写了一个函数“applyInterestChanges”来将数据保存在数据库中。我必须检索相同的数据来显示选定的复选框(我们是通过构造函数传递数据来完成的)。

如有任何帮助,我们将不胜感激!!

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Center(
          child: RaisedButton(
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => Interests(),
                ),
              );
            },
            child: Text("Click here!!"),
          ),
        ),
      ),
    );
  }
}

class Interests extends StatefulWidget {
  final List<dynamic> selectedList;
  final void Function(List<dynamic>) callback;

  Interests(this.selectedList, this.callback);

  @override
  _InterestsState createState() => _InterestsState();
}

class _InterestsState extends State<Interests> {
  Map<String, dynamic> _categories = {
    "responseCode": "1",
    "responseText": "List categories.",
    "responseBody": [
      {"category_id": "1", "category_name": "Movies"},
      {"category_id": "2", "category_name": "Sports"},
      {"category_id": "3", "category_name": "Food"},
      {"category_id": "4", "category_name": "Music"},
      {"category_id": "5", "category_name": "Others"},
    ],
    "responseTotalResult": 5
  };

  void _onCategorySelected(bool selected, categoryName) {
    if (selected == true) {
      setState(() {
        widget.selectedList.add(categoryName);
      });
    } else {
      setState(() {
        widget.selectedList.remove(categoryName);
      });
    }
    widget.callback(widget.selectedList);
  }

  applyInterestChanges() { //function to save the changes in database.
    Firestore.instance
        .collection('my_users')
        .document(currentUserModel.id)
        .updateData({
      "interests": widget.selectedList,
    });
  } //this code is working properly. Need to similar function to retrieve the data and display the updated interests list.

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Interests"),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            Text(
              "Select your interests: ",
              style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
            ),
            ListView.builder(
              physics: NeverScrollableScrollPhysics(),
              scrollDirection: Axis.vertical,
              shrinkWrap: true,
              itemCount: _categories['responseTotalResult'],
              itemBuilder: (BuildContext context, int index) {
                return CheckboxListTile(
                  controlAffinity: ListTileControlAffinity.leading,
                  value: widget.selectedList.contains(
                      _categories['responseBody'][index]['category_name']),
                  onChanged: (bool selected) {
                    _onCategorySelected(selected,
                        _categories['responseBody'][index]['category_name']);
                  },
                  title:
                      Text(_categories['responseBody'][index]['category_name']),
                );
              },
            ),
            MaterialButton(
              onPressed: () {
                Navigator.pop(context);
                applyInterestChanges();
              },
              child: Text("Submit"),
            ),
          ],
        ),
      ),
    );
  }
}

最佳答案

您可以从父小部件MyHomeWidget传递一个空列表,并通过Interests小部件的回调更新此列表。

下次,每当您返回并再次导航到Interests小部件时,我们都会传递此更新的列表,该列表保存Interests小部件的状态。因此,将根据列表中的值来检查复选框。

这里是实现:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class MyHomePage extends StatefulWidget {
  
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<dynamic> selectedList = [];
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Center(
          child: RaisedButton(
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => Interests(
                    selectedList,
                    (List<dynamic> updatedList) {
                      setState(() {
                        selectedList = updatedList;
                      });
                    }
                  ),
                ),
              );
            },
            child: Text("Click here!!"),
          ),
        ),
      ),
    );
  }
}

class Interests extends StatefulWidget {
  Interests(this.selectedList, this.callback);
  
  // Passing the list from parent widget i.e, MyHomeWidget
  // Initially the list will be empty
  // We will update the list in parent whenever checkboxes change
  final List<dynamic> selectedList;
  
  // Creating a callback function to save state(update list) in 
  // MyHomeWidget
  final void Function(List<dynamic>) callback;
  
  @override
  _InterestsState createState() => _InterestsState();
}

class _InterestsState extends State<Interests> {
  
  Map<String, dynamic> _categories = {
    "responseCode": "1",
    "responseText": "List categories.",
    "responseBody": [
      {"category_id": "1", "category_name": "Movies"},
      {"category_id": "2", "category_name": "Sports"},
      {"category_id": "3", "category_name": "Food"},
      {"category_id": "4", "category_name": "Music"},
      {"category_id": "5", "category_name": "Others"},
    ],
    "responseTotalResult": 5
  };

  void _onCategorySelected(bool selected, categoryId) {
    if (selected == true) {
      setState(() {
        widget.selectedList.add(categoryId);
      });
    } else {
      setState(() {
        widget.selectedList.remove(categoryId);
      });
    }
    
    // Callback to save the updated selectedList to MyHomeWidget list
    widget.callback(widget.selectedList);
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Interests"),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            Text(
              "Select your interests: ",
              style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
            ),
            ListView.builder(
              physics: NeverScrollableScrollPhysics(),
              scrollDirection: Axis.vertical,
              shrinkWrap: true,
              itemCount: _categories['responseTotalResult'],
              itemBuilder: (BuildContext context, int index) {
                return CheckboxListTile(
                  value: widget.selectedList.contains(
                      _categories['responseBody'][index]['category_id']),
                  onChanged: (bool selected) {
                    _onCategorySelected(selected,
                        _categories['responseBody'][index]['category_id']);
                  },
                  title:
                      Text(_categories['responseBody'][index]['category_name']),
                );
              },
            ),
            RaisedButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: Text("Go back!!"),
            ),
          ],
        ),
      ),
    );
  }
}

这是您想要从 Firebase 获取的方法。我使用了更新后的类 FirebaseFirestore。如果您使用的是旧版本的 Firebase,只需将 FirebaseFirestore 替换为 Firebase 即可。

Future<void> fetchInterestChanges() async { //function to get the changes in database.
    final DocumentSnapshot doc = await FirebaseFirestore.instance
        .collection('my_users')
        .document(currentUserModel.id)
        .get();
    
    final updatedList = doc.data();
    print(updatedList);
  }

关于firebase - Flutter:即使在屏幕之间导航后也会保存页面的状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64842446/

相关文章:

flutter - 如何在 Flutter 中设置默认选中的单选按钮?

java - 如何在android中创建我自己的com.google.android.gms.tasks.Task?

ios - 在 Swift 中采用 FIRGeoPoint 到 Codable 协议(protocol)

javascript - Firestore 更新数组字段中的单个项目

firebase - ListView.builder 仅在热重载 flutter 应用程序后加载

firebase - 如何使用 Http 缓存控制保存 Firestore 请求?

android - 将新条目添加到数据库时如何向服务器应用程序发送通知

javascript - 让客户端创建用户但在通过身份验证之前不修改

dart - Flutter - 点击检测 TextField

flutter - 关闭和打开应用程序后记住屏幕状态