首页 > 解决方案 > 如何在颤动中更改 StreamBuilder 中特定切换开关的状态

问题描述

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

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

每当他们点击开关按钮时,数据库中的数据就会更新。但不知道如何更改轻按的切换开关按钮的状态。

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

这是我的数据库结构。

Profiles(Children) 表结构。

Profiles(子)表结构

以下是出勤表结构。每个文档将每天以特定日期的名称创建。在每个文档配置文件中,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();
  }

标签: firebasefluttergoogle-cloud-firestorestatetoggleswitch

解决方案


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

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

推荐阅读