如果向下滑动以关闭,则 Flutter GestureDetector

问题描述

我希望能够向下滑动以关闭,但使用 Hero-Animation

我尝试使用这样的 GestureDetector

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

动画看起来不错,但问题是它几乎在任何手势下都是 poping。我想要的是它只有在用户实际向下滑动时才会弹出。

还应该有一些 finished 属性,以便在用户没有完全向下滑动时取消动画。这是可能的,如果是,如何?我找不到关于此的任何内容..

想要的结果应该是这样的:

Desired Animation

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

当前动画:

Screenvideo

通过单击关闭按钮,动画效果很好。 但是如果我开始拖动,动画应该开始,如果我结束它,它应该pop,或者我也可以取消动画并且动画恢复到正常屏幕。

这是我的代码,如果有帮助的话,这是完整的代码

 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。 简单的例子是:

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

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

编辑:

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

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...