我有一个用于检测手势的容器,这样我就可以像我这样用自定义绘画工具创建的图像滚动浏览
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的动画文档并使用开放源代码,但我仍然没有确定我将如何去做。有人可以阐明这个问题吗?
答案 0 :(得分: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轴上移动(在onHorizontalDragUpdate和End上使用),因此您可以使用primaryDelta和primaryVelocity值,这些值已经为您提供了在主轴上的位置和速度的计算(在这种情况下为水平)。
在onHorizontalDragUpdate中,您可以通过添加控制器的值来添加拖动的位置(正数表示您正远离第一次轻按的位置,负数表示您正向后移,0表示您尚未移动或拖动)。
在onHorizontalDragEnd中,您可以使用primaryVelocity和相同的逻辑来计算速度(正数表示您要移开,负数表示要返回,0表示没有速度,基本上是您在拖动结束之前停止了移动)。您可以使用模拟,也可以仅使用fling方法,并传递具有的速度(正值表示要结束动画,负值表示要消除动画的速度,而0表示不想移动)。
最后,您唯一需要做的就是将您无法与控制器一起移动的小部件包装在SlideTransition中,其中带有由控制器动画的Tween动画开始为零,然后在您要结束的位置结束(在我的情况下,想要从左向右移动