Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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,
      )
    ),
  );
}
like image 748
AK-23 Avatar asked Dec 22 '20 11:12

AK-23


2 Answers

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);
  }
}
like image 131
Till Friebe Avatar answered Sep 20 '22 15:09

Till Friebe


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);
  }
  .
  .
  .
}
like image 40
ltk Avatar answered Sep 16 '22 15:09

ltk