Flutter - DragBox 反馈动画到原始位置
Posted
技术标签:
【中文标题】Flutter - DragBox 反馈动画到原始位置【英文标题】:Flutter - DragBox Feedback animate to original position 【发布时间】:2019-06-06 05:37:05 【问题描述】:我想在 DropTarget 不接受时显示可拖动的反馈动画。Flutter 不显示反馈。有什么方法可以证明或控制它。像这个例子,我想达到这个效果。我以某种方式实现了这种效果,但是返回到原始偏移量并不正确。它正在向前移动到原来的位置。
我想要的动画效果。
这是我的代码,当我将它提升到某个位置并让他从那里离开时,我有一个拖动框,它应该动画回到原始位置,但它正在返回到像这样的其他偏移量。
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main()
runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(body: DragBox()),
);
class DragBox extends StatefulWidget
DragBox(
Key key,
) : super(key: key);
@override
State<StatefulWidget> createState()
return new _MyDragBox();
class _MyDragBox extends State<DragBox> with TickerProviderStateMixin
GlobalKey _globalKey = new GlobalKey();
AnimationController _controller;
Offset begin;
Offset cancelledOffset;
Offset _offsetOfWidget;
@override
void initState()
WidgetsBinding.instance.addPostFrameCallback((s)
_afeteLayout();
);
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 1000),
);
void _afeteLayout()
final RenderBox box = _globalKey.currentContext.findRenderObject();
Offset offset = -box.globalToLocal(Offset(0.0, 0.0));
_offsetOfWidget = offset;
@override
void dispose()
_controller.dispose();
super.dispose();
@override
Widget build(BuildContext context)
return Stack(
children: <Widget>[
Center(
child: Draggable(
key: _globalKey,
onDraggableCanceled: (v, o)
setState(()
cancelledOffset = o;
);
_controller.forward();
,
feedback: Container(
color: Colors.red,
height: 50,
width: 50,
),
child: Container(
color: Colors.red,
height: 50,
width: 50,
),
),
),
_controller.isAnimating
? SlideTransition(
position: Tween<Offset>(
begin: cancelledOffset * 0.01,
end: _offsetOfWidget * 0.01)
.animate(_controller)
..addStatusListener((status)
if (status == AnimationStatus.completed)
_controller.stop();
else
_controller.reverse();
),
child: Container(
color: Colors.red,
height: 50,
width: 50,
),
)
: Container(
child: Text('data'),
)
],
);
【问题讨论】:
这不是 Draggable 开箱即用的东西。你必须自己制作动画,使用OverlayEntry
和其他一些东西
@RémiRousselet 谢谢。如果您有任何示例,我会尝试一下,我会得到更多的想法?
@RémiRousselet ***.com/questions/54194412/… 你能帮我解决这个问题吗?
你能达到想要的动画效果吗?
你能详细说明你是如何实现它的吗?
【参考方案1】:
我认为,关于 "Animate a widget using a physics simulation" 的文档是最适合您想要实现的目标的示例。
这个秘籍演示了如何从拖动点移动小部件 使用弹簧模拟回到中心。
要实际体验它,请查看example:
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
void main()
runApp(MaterialApp(home: PhysicsCardDragDemo()));
class PhysicsCardDragDemo extends StatelessWidget
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(),
body: DraggableCard(
child: FlutterLogo(
size: 128,
),
),
);
/// A draggable card that moves back to [Alignment.center] when it's
/// released.
class DraggableCard extends StatefulWidget
final Widget child;
DraggableCard(required this.child);
@override
_DraggableCardState createState() => _DraggableCardState();
class _DraggableCardState extends State<DraggableCard>
with SingleTickerProviderStateMixin
late AnimationController _controller;
/// The alignment of the card as it is dragged or being animated.
///
/// While the card is being dragged, this value is set to the values computed
/// in the GestureDetector onPanUpdate callback. If the animation is running,
/// this value is set to the value of the [_animation].
Alignment _dragAlignment = Alignment.center;
late Animation<Alignment> _animation;
/// Calculates and runs a [SpringSimulation].
void _runAnimation(Offset pixelsPerSecond, Size size)
_animation = _controller.drive(
AlignmentTween(
begin: _dragAlignment,
end: Alignment.center,
),
);
// Calculate the velocity relative to the unit interval, [0,1],
// used by the animation controller.
final unitsPerSecondX = pixelsPerSecond.dx / size.width;
final unitsPerSecondY = pixelsPerSecond.dy / size.height;
final unitsPerSecond = Offset(unitsPerSecondX, unitsPerSecondY);
final unitVelocity = unitsPerSecond.distance;
const spring = SpringDescription(
mass: 30,
stiffness: 1,
damping: 1,
);
final simulation = SpringSimulation(spring, 0, 1, -unitVelocity);
_controller.animateWith(simulation);
@override
void initState()
super.initState();
_controller = AnimationController(vsync: this);
_controller.addListener(()
setState(()
_dragAlignment = _animation.value;
);
);
@override
void dispose()
_controller.dispose();
super.dispose();
@override
Widget build(BuildContext context)
final size = MediaQuery.of(context).size;
return GestureDetector(
onPanDown: (details)
_controller.stop();
,
onPanUpdate: (details)
setState(()
_dragAlignment += Alignment(
details.delta.dx / (size.width / 2),
details.delta.dy / (size.height / 2),
);
);
,
onPanEnd: (details)
_runAnimation(details.velocity.pixelsPerSecond, size);
,
child: Align(
alignment: _dragAlignment,
child: Card(
child: widget.child,
),
),
);
样本输出:
【讨论】:
嗨,这很好,但是如果您真的需要使用Draggable
小部件,因为您有需要 Draggable
的数据的 DragTarget
,该怎么办?【参考方案2】:
解决这个问题的一个简单方法是创建一个覆盖 Draggable 的小部件,并使其成为 AnimatedPositioned 的子级。示例如下:
import 'package:flutter/material.dart';
class XDraggable extends StatefulWidget
const XDraggable(
Key? key,
required this.child,
required this.original_x,
required this.original_y,
this.animation_speed = 200)
: super(key: key);
final Widget child;
final double original_x;
final double original_y;
final double animation_speed;
@override
_XDraggableState createState() => _XDraggableState();
class _XDraggableState extends State<XDraggable>
double x = 200;
double y = 200;
int animation_speed = 0;
@override
void initState()
x = widget.original_x;
y = widget.original_y;
super.initState();
@override
Widget build(BuildContext context)
return AnimatedPositioned(
left: x,
top: y,
duration: Duration(milliseconds: animation_speed),
child: Draggable(
onDragUpdate: (details) =>
setState(()
animation_speed = 0;
x = x + details.delta.dx;
y = y + details.delta.dy;
),
,
onDragEnd: (details)
setState(()
animation_speed = 200;
x = widget.original_x;
y = widget.original_y;
);
,
child: widget.child,
feedback: SizedBox(),
),
);
然后,只需将小部件用作 Stack 子项:
...
child: Stack(
fit: StackFit.expand,
children: [
XDraggable(
original_x: 20,
original_y: 20,
child: Container(
height: 50.0,
width: 50.0,
color: Colors.green,
),
)
],
),
...
【讨论】:
以上是关于Flutter - DragBox 反馈动画到原始位置的主要内容,如果未能解决你的问题,请参考以下文章