Flutter смахивание виджета с экрана

Доброго времени суток.

Подскажите пожалуйста, как сделать, чтобы виджет следовал за движением свайпа, а когда свайп завершиться, то я мог выполнить setState, чтобы скрыть виджет из дерева?

Я пытался сделать следующим образом, через GestureDetector по событию onVerticalDragEnd менял состояние и виджет скрывался, но мне нужно, чтобы виджет, пока пользователь продолжает движение пальца следовал за ним, то есть, добавить отзывчивость эдакую.

Попробовал сделать через событие onVerticalDragUpdate, достаю из него delta смещение и к элементу positioned добавляю это смещение в top параметр. Теперь работает следование за пальцем, но не работает событие onVerticalDragEnd.

Пытался использовать Draggable, но, как я понял, он тоже в этой ситуации не работает. Подскажите, пожалуйста, как реализовать такое окошко?

Код этого кусочка:

// Модальное окно (панелька) выбора
          if (_isChoiceModalOpen)
            Positioned(
              top: _modalTopOffset,
              child: GestureDetector(
                child: AppDrawerChoiceModalView(),
                onVerticalDragEnd: (_) => setState(() {
                  _isChoiceModalOpen = false;
                }),
                onVerticalDragUpdate: (DragUpdateDetails details) => setState((){
                  _modalTopOffset += details.delta.dy;
                }),
              ),
            ),

Оно лежит внутри Stack'а, поэтому Positioned работает.

Полный код с родительским виджетом:

class _AppDrawerViewState extends State<AppDrawerView> {

  late bool _isChoiceModalOpen;
  late double _modalTopOffset;

  @override
  void initState() {
    _isChoiceModalOpen = false;
    _modalTopOffset = 0.0;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final EdgeInsets notchInset = MediaQuery.of(context).padding;
    final Size size = MediaQuery.of(context).size;

    return Drawer(
      child: Stack(
        children: <Widget>[
          Container(
            color: AppColors.secondaryBackground,
            child: ListView(
              padding: EdgeInsets.zero,
              children: <Widget>[
                GestureDetector(
                  child: Image.asset("assets/screens/main/images/avatar.png"),
                  onTap: () => setState(() {
                    _isChoiceModalOpen = true;
                  }),
                ),
                Divider(
                  height: 3,
                  color: Colors.black,
                ),
                // Главная
                AppDrawerTileView(
                  icon: Icons.home_outlined,
                ),
                // Новости
                AppDrawerTileView(
                    icon: Icons.article_outlined,
                ),
                // Выход
                AppDrawerTileView(
                    icon: Icons.logout_outlined,
                ),
              ],
            ),
          ),

          // Модальное окно (панелька) выбора
          if (_isChoiceModalOpen)
            Positioned(
              top: _modalTopOffset,
              child: GestureDetector(
                child: AppDrawerChoiceModalView(),
                onVerticalDragEnd: (_) => setState(() {
                  _isChoiceModalOpen = false;
                }),
                onVerticalDragUpdate: (DragUpdateDetails details) => setState((){
                  _modalTopOffset += details.delta.dy;
                }),
              ),
            ),
        ]
      ),
    );
  }
}

Лишние элементы, виджеты и т.п. убрал, чтобы была понятна суть и не было совсем неразборчиво большого кода.

Здесь происходит следующее. При инициализации менюшки, модальное окно закрыто и отступ равен нулю. По нажатию на аватарке в шапке меню открывается модальное окошко.

GestureDetector(
                  child: Image.asset("assets/screens/main/images/avatar.png"),
                  onTap: () => setState(() {
                    _isChoiceModalOpen = true;
                  }),
                ),

Нужно сделать возможность его смахивать.


Ответы (1 шт):

Автор решения: Sergey K.

Нашёлся виджет для решения этой проблемы. Dismissible с параметром direction: DismissDirection.down

→ Ссылка