Flutter 如何在点击按钮时为 matrix4 翻译设置动画

Flutter how to animate matrix4 translate when button is tapped

我有 2 个按钮,用于控制 InteractiveViewer 小部件的左右滚动,希望在我对 matrix4Tween 有了更好的了解后,我可以自己添加上下滚动

现在按钮就是这样

       Row(
          children: [
            ElevatedButton(
              onPressed: () {
                controller.value = Matrix4.identity()..translate(0.0, 0.0);
              },
              child: Text('<'),
            ),
            ElevatedButton(
              onPressed: () {
                controller.value = Matrix4.identity()..translate(-(width), 0.0);
              },
              child: Text('>'),
            ),
          ],
        ),

下面是一个包含 4 个 gridview

的 interactiveViewer 小部件
     Container(
          color: Colors.grey,
          width: gridboxwidth,
          height: gridboxheight,
          child: InteractiveViewer(
            alignPanAxis: true,
            constrained: false,
            transformationController: controller,
            scaleEnabled: true,
            minScale: 0.1,
            maxScale: 1,
            child: Column(
              children: [
                Row(
                  children: [
                    grid1(size),
                    grid3(size),
                  ],
                ),
                Row(
                  children: [
                    grid2(size),
                    grid4(size),
                  ],
                ),
              ],
            ),
          ),
        ),

它工作得很好,点击按钮,网格就会进入视图,但我认为它不够直观,可能需要添加一些动画来显示网格已经改变。

非常感谢任何帮助和指导。

这是一个使用Matrix4Tween的示例小部件,重要的代码行标有// NOTE:注释:

class FooInteractiveViewer extends StatefulWidget {
  @override
  _FooInteractiveViewerState createState() => _FooInteractiveViewerState();
}

class _FooInteractiveViewerState extends State<FooInteractiveViewer> with TickerProviderStateMixin {
  AnimationController _ctrl;
  Animation<Matrix4> _matrixAnimation = AlwaysStoppedAnimation(Matrix4.identity());
  final _transformationController = TransformationController();

  @override
  void initState() {
    super.initState();
    _ctrl = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 500),
    )
      // NOTE: add listener to be called each time _ctrl changes
      ..addListener(_listener);
  }

  void _listener() {
    print(MatrixUtils.transformPoint(_matrixAnimation.value, Offset.zero));
    // NOTE: this is the most important part of this code:
    _transformationController.value = _matrixAnimation.value;
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        return InteractiveViewer(
          // panEnabled: false,
          alignPanAxis: true,
          constrained: false,
          transformationController: _transformationController,
          child: SizedBox(
            width: constraints.maxWidth * 2,
            height: constraints.maxHeight * 2,
            child: Column(
              children: [
                Expanded(
                  child: Row(
                    children: [
                      button(Colors.red, constraints.biggest, 1, 0, 'green'),
                      button(Colors.green, constraints.biggest, 0, 1, 'blue'),
                    ],
                  ),
                ),
                Expanded(
                  child: Row(
                    children: [
                      button(Colors.blue, constraints.biggest, 1, 1, 'orange'),
                      button(Colors.orange, constraints.biggest, 0, 0, 'red'),
                    ],
                  ),
                ),
              ],
            ),
          )
        );
      },
    );
  }

  Widget button(Color color, Size size, int x, int y, String name) {
    return Expanded(
      child: Material(
        color: color,
        child: InkWell(
          onTap: () async {
            // timeDilation = 10;
            // NOTE: create new Animation<Matrix4> that will be used inside _listener
            _matrixAnimation = Matrix4Tween(
              begin: _transformationController.value,
              end: Matrix4.translationValues(-size.width * x, -size.height * y, 0)
            ).chain(CurveTween(curve: Curves.decelerate)).animate(_ctrl);
            // NOTE: lets start the show
            await _ctrl.forward(from: 0);
            print('### animation finished ###');
          },
          child: Center(child: Text('go to $name', textScaleFactor: 2)),
        ),
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
    _ctrl.dispose();
  }
}