2

我有一个容器,我在其上检测手势,以便我可以滚动浏览我使用自定义画家创建的图像,就像这样

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 的动画文档并玩弄开源代码,但我仍然没有确定我将如何去做。任何人都可以对这个问题有所了解吗?

4

1 回答 1

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 轴上移动(您正在使用Horizo​​ntalDragUpdate 和 End),因此您可以使用值 primaryDelta 和 primaryVelocity,这已经为您提供了主轴中位置和速度的计算(在此水平案子)。

在 onHorizo​​ntalDragUpdate 中,您将控制器值添加到拖动的位置(正的您正在远离您第一次点击的位置,负的您正在向后移动,0 您没有移动或拖动)。

在 onHorizo​​ntalDragEnd 中,您使用primaryVelocity 和相同的逻辑计算速度(正的您正在离开,负的您正在返回,0 没有速度,基本上您在拖动结束之前停止移动)。您可以使用模拟或仅使用投掷方法并传递您拥有的速度(正数您想要结束动画,负数您想要关闭它,0 您不想移动)。

最后,您唯一需要做的就是将您无法与控制器一起移动的小部件包装在 SlideTransition 中,其中控制器动画的 Tween 从零开始并在您想要结束的位置结束(在我的情况下,我想移动从左到右)

于 2020-07-02T01:08:19.097 回答