Flutter GestureDetector(向下滑动以将其关闭) [英] Flutter GestureDetector if swiping down to dismiss

查看:250
本文介绍了Flutter GestureDetector(向下滑动以将其关闭)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够向下滑动以退出,但使用 Hero-Animation .

I would like to be able to swipe down to dismiss but with the Hero-Animation.

我尝试像这样使用 GestureDetector :

  body: GestureDetector(
    onVerticalDragDown: (details) {
      Navigator.pop(context);
    },
    child: 

此动画看上去不错,但问题在于它几乎可以以任何姿势弹出 popping .我想拥有的是,它只会在用户实际向下滑动时弹出.

The animation looks fine with this but the problem is that it is poping at almost any gesture. What I would like to have is that it is only popping if the user is actually swiping down.

还应该有一些 finished 属性,因此,如果用户没有完全向下滑动,则动画将被取消.这可能吗?如果可以,怎么办?我找不到任何东西.

There should be some finished property as well so the animation is canceled if the user is not fully swiping down. Is this possible and if so, how? I couldn't find anything on this..

所需的结果应如下所示:

The desired outcome should look like this:

所需的动画

如您所见,我可以向下滑动,也可以通过不完全向下滑动来取消 pop .

As you can see I can swipe down and also cancel the pop by not fully swiping down.

当前动画:

屏幕录像

通过单击关闭按钮,动画运行正常.但是,如果我开始拖动,动画应该开始,如果我结束动画,它应该 pop ,否则我也可以取消动画并将动画恢复到正常屏幕.

By clicking the close button the animation is working just fine. However if I start dragging, the animation should start, and if I end it, it should pop, or I could also cancel the animation and the animation is restored to the normal screen.

这是我的代码,如果有帮助,则为完整代码:

This is my code if that is full code if that is helping:

 Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onVerticalDragDown: (details) {
          Navigator.pop(context);
        },
        child: Stack(
          children: [
            Hero(
              tag: month.name + 'background',
              // transitionOnUserGestures: true,
              child: Container(
                // color: CustomColors.darkCustom,
                decoration: BoxDecoration(
                  color: CustomColors.darkCustom,
                  borderRadius: BorderRadius.circular(30.0),
                ),
              ),
            ),
            Positioned(
              right: 30,
              top: 15,
              child: SafeArea(
                child: Hero(
                  // transitionOnUserGestures: true,
                  tag: month.name + 'close',
                  child: Container(
                    height: 45,
                    width: 45,
                    child: RawMaterialButton(
                      fillColor: CustomColors.lightGreyCustom,
                      splashColor: Colors.transparent,
                      highlightColor: Colors.transparent,
                      // elevation: 10,
                      shape: CircleBorder(),
                      onPressed: () {
                        Navigator.of(context).pop();
                      },
                      child: SvgPicture.asset('assets/images/close.white.svg',
                          height: 25, width: 25),
                    ),
                  ),
                ),
              ),
            ),
            Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                SafeArea(
                  bottom: false,
                  child: SizedBox(height: 20),
                ),
                Row(
                  children: [
                    Padding(
                      padding:
                          const EdgeInsets.only(left: 45, top: 45, bottom: 35),
                      child: Hero(
                        // transitionOnUserGestures: true,
                        tag: month.name + 'text',
                        // sized box to prevent flickering bug
                        child: SizedBox(
                          height: 40,
                          width: 200,
                          // material is need for Hero + Text
                          child: Material(
                            color: Colors.transparent,
                            child: Text(
                              month.name,
                              style: TextStyle(
                                color: Colors.white,
                                fontSize: 28,
                                fontFamily: Fonts.glossAndBloom,
                              ),
                            ),
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
                Hero(
                  tag: month.name + 'frame',
                  child: Container(
                    height: Constants.width(context) - 60,
                    width: Constants.width(context) - 60,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(10.0),
                      border: Border.all(color: Colors.white, width: 5),
                    ),
                  ),
                ),
              ],
            )
          ],
        ),
      ),
    );
  }

在Swift中,我使用以下代码成功制作了动画:

@objc private func handlePan(gestureRecognizer:UIPanGestureRecognizer) {
    // calculate the progress based on how far the user moved
    let translation = panGR.translation(in: nil)
    let progress = translation.y / 2 / view.bounds.height
    
    switch panGR.state {
    case .began:
        // begin the transition as normal
        self.dismissView()
        break
    case .changed:
        
        Hero.shared.update(progress)
        
    default:
        // finish or cancel the transition based on the progress and user's touch velocity
        if progress + panGR.velocity(in: nil).y / view.bounds.height > 0.3 {
            self.dismissView()
            Hero.shared.finish()
        } else {
            Hero.shared.cancel()
        }
    }
}

推荐答案

我建议使用回调函数的DragEndDetails.一个简单的例子是:

I suggest to use DragEndDetails of the callback function. Simple example will be:

onVerticalDragEnd: (endDetails) {
              double velocity = endDetails.primaryVelocity;
              if (velocity > 0 ){                              
               Navigator.pop(context);
              }
            },

在这种情况下,如果您最后按住拖动手势,则不会弹出,因为速度等于0.

In this case if you hold the drag gesture at the end it will not pop because velocity will be equal to 0.

这是在拖动细节上实现动画的简单示例.在DragUpdate上,将调整容器的高度,但限制为max:300到min:100.在DragEnd上,取决于您向上或向下滑动,容器的高度将设置为最大或最小.

This is an simple example of implementing animation on drag details. On DragUpdate container height will be adjusted but with limit of max:300 to min:100. On DragEnd depends on either you swipe up or down the container height will be set to max or min.

class AnimatedContainerApp extends StatefulWidget {
  @override
  _AnimatedContainerAppState createState() => _AnimatedContainerAppState();
}

class _AnimatedContainerAppState extends State<AnimatedContainerApp> {
  double height = 300;
  bool gestureUp = false;
  
  @override
  Widget build(BuildContext context) {
    final maxHeight = 300.0;
    final minHeight = 100.0;
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('AnimatedContainer Demo'),
        ),
        body: Align(alignment: Alignment.bottomCenter,             
         child:AnimatedContainer(
          color: Colors.red,
            height: height,
            duration: Duration(milliseconds: 200),
            curve: Curves.fastOutSlowIn,
            child: GestureDetector(
               onVerticalDragUpdate: (details) {
                 setState((){
                  if (0 < details.delta.dy)
                    gestureUp = false;
                  else
                    gestureUp = true;
                  height -= details.delta.dy;
                  if (height > maxHeight)
                      height = maxHeight;
                  else if (height < minHeight)
                      height = minHeight;
                  });     
                },
                onVerticalDragEnd: (details) {
                  setState((){
                      if (gestureUp) {
                        height = maxHeight;
                      } else {
                        height = minHeight;
                      }
                    });     
                },
            )
          ),
        ),
      ),
    );
  }
}

这篇关于Flutter GestureDetector(向下滑动以将其关闭)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆