Как изменить состояние определенного переключателя внутри StreamBuilder во флаттере

Я создаю приложение для отслеживания школьных услуг с помощью Flutter. Поскольку я новичок в разработке мобильных приложений, я сталкиваюсь с множеством ошибок. Один из них является,

После того, как пользователь вошел в приложение, на панели инструментов он отобразит профили его детей в виде карточного виджета. Каждый профиль как кнопка переключателя для обновления их посещаемости.

Каждый раз, когда они нажимают на кнопку переключателя, данные обновляются в базе данных. Но не знаю, как изменить состояние нажатой кнопки тумблера.

Я использую базу данных Google Firebase Firestore.

Это моя структура базы данных.

Структура таблицы Profiles (Children).

Структура таблицы профилей (дочерних)

Ниже представлена ​​структура таблицы посещаемости. Каждый документ будет создаваться ежедневно под названием определенной даты. Внутри каждого профиля идентификаторы документов хранятся в виде вложенных коллекций.

Структура таблицы посещаемости

Внутри каждой субколлекции профиля под именем профиля будет содержаться информация о посещаемости.

введите здесь описание изображения

Вот как я получаю данные из базы данных.

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

person Thanooshan    schedule 25.03.2019    source источник


Ответы (1)


В вашей текущей реализации состояние переключателя не отражает значение базы данных, поскольку нет подписки на данные, которые обновляют его значение. Вы можете сделать виджет UserCard без состояния и вместо этого просто прочитать значение 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
              });
            });
          },
        );
      },
    )
person Dennis Alund    schedule 25.03.2019
comment
Оцените ваш быстрый ответ. Появляется всплывающее окно с ошибкой. Another exception was thrown: type 'DocumentSnapshot' is not a subtype of type 'bool' - person Thanooshan; 25.03.2019
comment
Да, извините, произошла ошибка в присвоении значения. Попробуйте посмотреть, работает ли сейчас строка с присвоением значения Switch лучше. - person Dennis Alund; 25.03.2019
comment
Ты мужчина. Работает отлично. Произошла небольшая ошибка. После того, как я изменил метод получения таким образом, он заработал .snap.data["attendance_status"] - person Thanooshan; 25.03.2019
comment
Рад слышать! Я обновил ответ, чтобы отразить это :-) - person Dennis Alund; 25.03.2019