Flutter: enable image zoom in/out on double tap using InteractiveViewer

4,708

Solution 1

You can use a GestureDetector, that gives you the position of the click and with that you can zoom with the TransformationController at the click position:

final _transformationController = TransformationController();
TapDownDetails _doubleTapDetails;

@override
Widget build(BuildContext context) {
  return GestureDetector(
    onDoubleTapDown: _handleDoubleTapDown,
    onDoubleTap: _handleDoubleTap,
    child: Center(
      child: InteractiveViewer(
        transformationController: _transformationController,
        /* ... */
      ),
    ),
  );
}

void _handleDoubleTapDown(TapDownDetails details) {
  _doubleTapDetails = details;
}

void _handleDoubleTap() {
  if (_transformationController.value != Matrix4.identity()) {
    _transformationController.value = Matrix4.identity();
  } else {
    final position = _doubleTapDetails.localPosition;
    // For a 3x zoom
    _transformationController.value = Matrix4.identity()
      ..translate(-position.dx * 2, -position.dy * 2)
      ..scale(3.0);
    // Fox a 2x zoom
    // ..translate(-position.dx, -position.dy)
    // ..scale(2.0);
  }
}

Solution 2

To animate the transition on double tap, you have to create an explicit animation on top of Till's code.

class _WidgetState extends State<Widget> with SingleTickerProviderStateMixin {
  .
  .
  .  
  AnimationController _animationController;
  Animation<Matrix4> _animation;
  
  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 400),
    )..addListener(() {
        _transformationController.value = _animation.value;
      });
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }
  .
  .
  .
  void _handleDoubleTap() {
    Matrix4 _endMatrix;
    Offset _position = _doubleTapDetails.localPosition;

    if (_transformationController.value != Matrix4.identity()) {
      _endMatrix = Matrix4.identity();
    } else {
      _endMatrix = Matrix4.identity()
        ..translate(-_position.dx * 2, -_position.dy * 2)
        ..scale(3.0);
    }

    _animation = Matrix4Tween(
      begin: _transformationController.value,
      end: _endMatrix,
    ).animate(
      CurveTween(curve: Curves.easeOut).animate(_animationController),
    );
    _animationController.forward(from: 0);
  }
  .
  .
  .
}
Share:
4,708
AK-23
Author by

AK-23

Humble.

Updated on December 26, 2022

Comments

  • AK-23
    AK-23 over 1 year

    I want to enable zoom in and out on double tap of the image, together with scaling in/out on pinch. I saw some tutorials on YouTube where they implemented this feature using GestureDetector like this one but for some reason, it didn't work out for me. In order to implement scaling in/out on pinch, I relied on this answer, and it really works well, but I also want to enable zoom in/out on double tapping the image. Looking up a way to do so on the internet, unfortunately, yielded nothing.

    Is there any way to enable zoom in/out with both pinch and double tap using InteractiveViewer?

    here is my code:

    @override
    Widget build(BuildContext context) {
      return Center(
        child: InteractiveViewer(
          boundaryMargin: EdgeInsets.all(80),
          panEnabled: false,
          scaleEnabled: true,
          minScale: 1.0,
          maxScale: 2.2,
          child: Image.network("https://pngimg.com/uploads/muffin/muffin_PNG123.png",
            fit: BoxFit.fitWidth,
          )
        ),
      );
    }