Handling gesture conflicts between PageView and InteractiveViewer in Flutter

63 views Asked by At

In my Flutter application, I'm using both PageView and InteractiveViewer to display and interact with images. I've encountered an issue where, after zooming into an image using InteractiveViewer, if I try to drag the image, the page switches immediately. This behavior seems to be due to a gesture conflict between PageView and InteractiveViewer.

What I've tried:

  • I've looked into the gestures of both widgets to see if there's a way to prioritize one over the other.
  • I've checked the following StackOverflow post which suggests executing paging only when the image is not zoomed in: link. However, this is not the behavior I want.

Expected Behavior: Even when the image is zoomed in, I want the application to switch to the next page only if I drag to the very edge of the zoomed image.

Actual Behavior: Currently, after zooming in, any drag gesture immediately switches the page.

Any suggestions or solutions to handle this gesture conflict would be greatly appreciated.

What I was expecting:

  • I wanted a solution where, even when the image is zoomed in using InteractiveViewer, the application would switch to the next page only if I drag to the very edge of the zoomed image.
  • Instead of the current behavior where, after zooming in, any drag gesture immediately switches the page.

mycode:

import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:preload_page_view/preload_page_view.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'PhotoView + Interactiveviewer',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const GalleryExample(),
    );
  }
}

class GalleryExample extends StatefulWidget {
  const GalleryExample({super.key});

  @override
  _GalleryExampleState createState() => _GalleryExampleState();
}

class _GalleryExampleState extends State<GalleryExample> {
  late int selectedIndex;
  final TransformationController _transformationController = TransformationController();
  late TapDownDetails _doubleTapDetails;

  List<String> pageItems = [
    "https://user0514.cdnw.net/shared/img/thumb/12redsugar721_TP_V.jpg",
    "https://user0514.cdnw.net/shared/img/thumb/05redsugar721_TP_V.jpg"
  ];

  void _handleDoubleTap() {
    print("double tap");
    final currentScale = _transformationController.value.getMaxScaleOnAxis();
    if (currentScale > 1.0) {
      _transformationController.value = Matrix4.identity();
    } else {
      final position = _doubleTapDetails.localPosition;
      _transformationController.value = Matrix4.identity()
        ..translate(-position.dx, -position.dy)
        ..scale(2.0);
    }
  }

  @override
  void initState() {
    super.initState();
    selectedIndex = 0;
  }

  @override
  Widget build(
    BuildContext context,
  ) {
    return Scaffold(
        backgroundColor: Colors.black,
        body: GestureDetector(
          behavior: HitTestBehavior.opaque,
          child: SafeArea(
            child: Stack(
              children: [
                Container(
                  color: Colors.black,
                  child: PageView.builder(
                    pageSnapping: true,
                    reverse: true,
                    itemCount: pageItems.length,
                    itemBuilder: (context, index) {
                      return LayoutBuilder(
                        builder: (BuildContext context, BoxConstraints constraints) {
                          return InteractiveViewer(
                            maxScale: 5.0,
                            minScale: 1.0,
                            transformationController: _transformationController,
                            onInteractionEnd: (details) {
                              if (_transformationController.value.getMaxScaleOnAxis() == 1.0) {
                                _transformationController.value = Matrix4.identity();
                              }
                            },
                            child: GestureDetector(
                              onDoubleTapDown: (details) {
                                _doubleTapDetails = details;
                              },
                              onDoubleTap: _handleDoubleTap,
                              child: Image.network(
                                pageItems[index],
                                fit: BoxFit.contain,
                              ),
                            ),
                          );
                        },
                      );
                    },
                  ),
                )
              ],
            ),
          ),
        ));
  }
}

0

There are 0 answers