Flutter GestureDetector(向下滑动以将其关闭) [英] Flutter GestureDetector if swiping down to dismiss
问题描述
我希望能够向下滑动以退出,但使用 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屋!