Как добиться удаления и отмены операций над удаляемым виджетом в Flutter?

#flutter

#flutter

Вопрос:

Вопросы:

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

Отклоненный удаляемый виджет по-прежнему является частью дерева.

Я искал решение этой проблемы, но ни одно из них не подходит для моего случая, потому что я использую Bloc для этих операций, а другие решения касались setState

Вы можете посмотреть здесь: GIF

2-) Также, когда я провожу пальцем по цвету фона карты, обрезается: Фото

Как исправить эти проблемы?

 return Dismissible(
  key: Key(widget.task.id.toString()),
  background: Container(
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(8),
      color: Colors.red,
    ),
  ),
  onDismissed: (direction) async {
    Task copied = widget.task;
    taskBloc.deleteTask(widget.task.id);
    changeValue(widget.task.categoryId, false);
    Flushbar(
      messageText: Text('Task deleted', style: bodyText.copyWith(
        color: Colors.white
      )),
      duration: Duration(seconds: 10),
      margin: EdgeInsets.all(8),
      borderRadius: 8,
      icon: Icon(FontAwesomeIcons.infoCircle, color: widget.color),
      flushbarStyle: FlushbarStyle.FLOATING,
      dismissDirection: FlushbarDismissDirection.HORIZONTAL,
      mainButton: FlatButton(
        onPressed: () async {
          taskBloc.addTask(copied);
          changeValue(widget.task.categoryId, true);
        },
        child: Text('Undo', style: bodyText.copyWith(color: widget.color)),
      ),
    )..show(context);
  }),
  

Ответ №1:

Вы можете добиться этого, передав confirmDismiss в удаляемый виджет, как указано ниже, который должен возвращать либо true, либо false;

  confirmDismiss: (val) async {    
 return await  AlertDialog(
      title: Text('Delete'),
      content: Text('Are you sure to delete?'),
      actions:[
        FlatButton(
          child:Text("Yes"),
          onPressed:()=>Navigator.pop(context,true)
        ),
         FlatButton(
          child:Text("No"),
          onPressed:()=>Navigator.pop(context,false)
        ),
      ],
    )??false;    
 }
  

После этого onDismissed вызывается только при нажатии кнопки Yes . после вызова dismissed элемент удаляется из текущего списка

Комментарии:

1. спасибо за ответ @Khadga, но я не хочу показывать диалоговое окно, я просто хочу показать панель управления (своего рода панель закусок), и если пользователь нажимает кнопку отмены, я должен вернуть ее, иначе она должна быть удалена

2. Кроме того, поскольку я использую StreamBuilder для удаления, я думаю, что нет необходимости удалять элемент из списка, потому что StreamBuilder уже обновляется, когда что-либо меняется (например, удаление элемента или добавление элемента)

3. @WildHunter Как вы этого добились. Можете ли вы поделиться с нами? Я также сталкиваюсь с такой же проблемой. Я использую SnackBar и повторно вставляю, когда пользователь нажимает кнопку отмены.

Ответ №2:

 void _onDismissed(BuildContext context, index) => setState(
    () {
      FavouriteSong favouriteSong = favouriteSongs[index];
      favouriteSongs.removeAt(index);
      BlocProvider.of<FavouriteSongBloc>(context)
          .add(DeleteFavouriteSong(favouriteSong: favouriteSong));

      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content:
              AutoSizeText("${favouriteSong.title} ကိုဖျက်လိုက်ပါပြီ။"),
          duration: const Duration(seconds: 3),
          action: SnackBarAction(
            label: 'မဖျက်တော့ပါ',
            onPressed: () {
              favouriteSongs.insert(index, favouriteSong);

              BlocProvider.of<FavouriteSongBloc>(context).add(
                CreateFavouriteSong(favouriteSong: favouriteSong),
              );
            },
          ),
        ),
      );
    },
  );
  

Ответ №3:

Вы просто забываете удалить элемент в текущий список и обновить с помощью setState(() {})

 return Dismissible(
  key: Key(widget.task.id.toString()),
  background: Container(
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(8),
      color: Colors.red,
    ),
  ),
  onDismissed: (direction) async {
    Task copied = widget.task;
    taskBloc.deleteTask(widget.task.id);
    changeValue(widget.task.categoryId, false);
    setState(() {})
    Flushbar(
      messageText: Text('Task deleted', style: bodyText.copyWith(
        color: Colors.white
      )),
      duration: Duration(seconds: 10),
      margin: EdgeInsets.all(8),
      borderRadius: 8,
      icon: Icon(FontAwesomeIcons.infoCircle, color: widget.color),
      flushbarStyle: FlushbarStyle.FLOATING,
      dismissDirection: FlushbarDismissDirection.HORIZONTAL,
      mainButton: FlatButton(
        onPressed: () async {
           // to success rollback you must change id because of (Key(widget.task.id.toString())),
           // otherwise you will get the same error
          taskBloc.addTask(copied);
          changeValue(widget.task.categoryId, true);
        },
        child: Text('Undo', style: bodyText.copyWith(color: widget.color)),
      ),
    )..show(context);
  }),