如何在 flutter 中更改 StreamBuilder 中特定切换开关的状态

How to change the state of an particular toggle switch inside the StreamBuilder in flutter

我正在使用 Flutter 构建一个学校服务跟踪应用程序。由于我是移动应用程序开发的新手,所以我遇到了很多错误。其中之一是,

用户登录应用程序后,在仪表板中,它将在卡片小部件中显示他们的 children 个人资料。每个个人资料作为切换开关按钮来更新他们的出勤率。

只要他们点击切换按钮,数据库中的数据就会更新。但是不知道如何改变点击的拨动开关按钮的状态。

我正在使用 Google Firebase Firestore 数据库。

这是我的数据库结构。

个人资料(Children)table 结构。

以下是出勤 table 结构。每个文档将在特定日期的名称下每天创建。在每个文档配置文件 ids 中存储为子集合。

在每个个人资料子集合中,一个文档将在个人资料名称下包含出勤详细信息。

这就是我从数据库中检索数据的方式。

       CustomScrollView(
          slivers: <Widget>[
            SliverList(
              delegate: SliverChildListDelegate([
                whiteLogo(), // this is a logo widget
              ]),
            ),
            StreamBuilder(
              stream: Firestore.instance.collection('profiles').snapshots(),
              builder: (context, snapshot) => SliverList(
                  delegate: SliverChildBuilderDelegate((context, index) =>
                    Container(
                      child: userCard(context, snapshot.data.documents[index]), // profile card
                    ),
                  childCount: snapshot.hasData ? snapshot.data.documents.length : 0,
                ),
              )
            )
          ],
        )

以下是 userCard 小部件

    userCard(BuildContext context, DocumentSnapshot document) {

    var attendanceCollection = Firestore.instance.collection('attendance').document('10-01-2019').collection(document.documentID);

    var documentId = document["name"].toString().toLowerCase();

    var attendanceReference = attendanceCollection.document(documentId);

    bool status = true;


    return Card(
      margin: EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 20.0),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.all(Radius.circular(10.0)),
      ),
      elevation: 0.3,
      color: Colors.white,
      child: Padding(
        padding: EdgeInsets.fromLTRB(5.0, 15.0, 5.0, 10.0),
        child: Column(
          children: <Widget>[
            ListTile(
              leading: (
                Container(
                  width: 50.0,
                  height: 50.0,
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    image: DecorationImage(
                      fit: BoxFit.cover,
                      image: NetworkImage(
                        '${document['avatar']}'
                      )
                    ),
                  ),
                )
              ),
              title: Text(document['name']),
              trailing: Column(
                children: <Widget>[
                  Text(
                    'Absent/Present',
                    style: TextStyle(
                      color: Color(0xff868686),
                      fontSize: 12.0
                    ),
                  ),
                  Switch(value: status, onChanged: (value) {

                    setState(() {
                      status = value;
                    });

                    //onChange the "attendance_status" value is changing

                    Firestore.instance.runTransaction((transaction) async {
                      DocumentSnapshot freshSnap = await transaction.get(attendanceReference);
                      await transaction.update(freshSnap.reference, {
                        "attendance_status": value
                      });
                    });


                  },)
                ],
              ),
            ),
            horizontalLine(),
            textTile('School', 'Class', 13.0, Color(0xff827f7f)),
            Container(margin: EdgeInsets.only(bottom: 10.0)),
            textTile(document['destination'], document['class'], 16.0, Color(0xff424242)),
            horizontalLine(),
            buttonWrap(context, document)
          ],
        ),
      ),
    );
}

这是仪表板的预览。

当我点击切换开关按钮时,它会更新数据库中的值。但不是按钮的状态。按钮状态没有改变。

我通过将 status 变量放在 initState 中进行了测试,但随后该状态影响了所有按钮。

我想在用户点击时更改特定切换开关按钮的状态。任何帮助将不胜感激。

  initState() {
    status = true;
    super.initState();
  }

在您当前的实现中,开关状态未反映数据库的值,因为没有订阅正在更新其值的数据。您可以使 UserCard 小部件无状态,只使用 StreamBuilder 从出勤集合中读取 Switch 的值。

像这样应该可以解决问题,您的考勤开关将根据考勤文件设置其状态(如果尚未创建文件,则应设置为 false

Column(
  children: <Widget>[
    Text(
      'Absent/Present',
      style: TextStyle(
        color: Color(0xff868686),
        fontSize: 12.0
      ),
    ),

    StreamBuilder(
      stream: attendanceReference.snapshots(),
      initialData: null,
      builder: (ctx, snap) {
        return Switch(
          value: snap.data == null ? false : snap.data["attendance_status"],
          onChanged: (value) {
            Firestore.instance.runTransaction((transaction) async {
              DocumentSnapshot freshSnap = await transaction.get(attendanceReference);
              await transaction.update(freshSnap.reference, {
                "attendance_status": value
              });
            });
          },
        );
      },
    )