如何向 CustomPainter 添加投掷动画?
Posted
技术标签:
【中文标题】如何向 CustomPainter 添加投掷动画?【英文标题】:How to add fling animation to CustomPainter? 【发布时间】:2020-07-01 17:54:51 【问题描述】:我有一个容器,我在其上检测手势,这样我就可以滚动浏览我使用自定义画家创建的图像,就像这样
class CustomScroller extends StatefulWidget
@override
_CustomScrollerState createState() => _CustomScrollerState();
class _CustomScrollerState extends State<CustomScroller>
with SingleTickerProviderStateMixin
AnimationController _controller;
double dx = 0;
Offset velocity = Offset(0, 0);
double currentLocation = 0;
@override
void initState()
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
super.initState();
Widget build(BuildContext context)
Size size = MediaQuery.of(context).size;
double width = MediaQuery.of(context).size.width;
return GestureDetector(
onHorizontalDragUpdate: (DragUpdateDetails dragUpdate)
dx = dragUpdate.delta.dx;
currentLocation =
currentLocation + (dx * 10000) / (width * _absoluteRatio);
setState(() );
,
onHorizontalDragEnd: (DragEndDetails dragUpdate)
velocity = dragUpdate.velocity.pixelsPerSecond;
//_runAnimation(velocity, size);
,
child: Container(
width: width,
height: 50,
child: Stack(
children: <Widget>[
CustomPaint(
painter: NewScrollerPainter(1, true, currentLocation),
size: Size.fromWidth(width)),
],
),
),
);
我编写了一些代码,以便在拖动时使用指针的 dx 值来计算 currentLocation,customPainter 'NewScrollerPaint' 使用它来确定需要绘制的区域。 我本质上想要一个投掷动画,即从一个速度的拖动中释放,自定义画家“NewScrollerPainter”将继续滚动,直到它失去动力。我相信这需要从速度计算 currentLocation 的值,然后返回以更新 NewScrollerPainter,但我花了几个小时查看 Flutter 的动画文档并玩弄开源代码,但我仍然没有确定我将如何去做。谁能解释一下这个问题?
【问题讨论】:
【参考方案1】:class CustomScroller extends StatefulWidget
@override
_CustomScrollerState createState() => _CustomScrollerState();
class _CustomScrollerState extends State<CustomScroller>
with SingleTickerProviderStateMixin
AnimationController _controller;
@override
void initState()
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
super.initState();
Widget build(BuildContext context)
double width = MediaQuery.of(context).size.width;
return GestureDetector(
onHorizontalDragUpdate: (DragUpdateDetails dragUpdate)
_controller.value += dragUpdate.primaryDelta / width;
,
onHorizontalDragEnd: (DragEndDetails dragEnd)
final double flingVelocity = dragEnd.primaryVelocity / width;
const spring = SpringDescription(
mass: 30,
stiffness: 1,
damping: 1,
);
final simulation = SpringSimulation(spring, _controller.value, 0, flingVelocity); //if you want to use a spring simulation returning to the origin
final friction = FrictionSimulation(1.5, _controller.value, -(flingVelocity.abs())); //if you want to use a friction simulation returning to the origin
//_controller.animateWith(friction);
//_controller.animateWith(simulation);
_controller.fling(velocity: -(flingVelocity.abs())); //a regular fling based on the velocity you were dragging your widget
,
child: Stack(
children: [
SlideTransition(
position: Tween<Offset>(begin: Offset.zero, end: const Offset(1, 0))
.animate(_controller),
child: Align(
alignment: Alignment.centerLeft,
child: CustomPaint(
painter: NewScrollerPainter(),
size: Size.fromWidth(width),
child: SizedBox(width: width, height: 50)
),
)
)
]
)
);
我看到您试图仅在 X 轴上移动(您使用的是水平拖动更新和结束),因此您可以使用值 primaryDelta 和 primaryVelocity,这已经为您提供了主轴上位置和速度的计算(在这种情况下是水平的)。
在 onHorizontalDragUpdate 中,您将控制器值添加到拖动的位置(正数表示您正在远离您第一次点击的位置,负数表示您正在向后移动,0 表示您没有移动或拖动)。
在 onHorizontalDragEnd 中,您使用 primaryVelocity 和相同的逻辑计算速度(正数表示您正在离开,负数表示您正在返回,0 没有速度,基本上您在拖动结束之前停止移动)。您可以使用模拟或仅使用 fling 方法并传递您拥有的速度(正值表示您想要结束动画,负值表示您想要关闭动画,0 表示您不想移动)。
最后,您唯一需要做的就是将您无法随控制器一起移动的小部件包装在 SlideTransition 中,其中控制器动画的 Tween 从零开始并在您想要结束的位置结束(在我的情况下,我想从左向右移动)
【讨论】:
这不是我想要的效果,但我已经想通了。我在这里重新提出了我的问题:***.com/questions/62713997/… 并且我注意到您之前回答了一个类似的问题,所以我希望您也可以在这个问题上帮助我。谢谢以上是关于如何向 CustomPainter 添加投掷动画?的主要内容,如果未能解决你的问题,请参考以下文章