0

I use InteractiveViewer inside the SingleChildScrollView, this is my full code:

import 'package:flutter/material.dart';
import '../constants/images.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final List<String> images = [Images.IMG1, Images.IMG2, Images.IMG3];

  MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: SingleChildScrollView(
          child: Column(
            children: [
              for (var image in images) ...[
                SizedBox(width:double.infinity,child: Divider(thickness: 5,)),
                Row(
                  children: [
                    Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: ClipOval(
                        child: CircleAvatar(
                          radius: 24,
                          child: Image.asset(Images.PROFILE_IMAGE),
                        ),
                      ),
                    ),
                    Text('User1'),
                  ],
                ),
                InteractiveViewer(
                    child: Image.asset(
                  image,
                  fit: BoxFit.fitWidth,
                )),
                Row(
                  children: [
                    Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Icon(Icons.favorite),
                    ),
                    Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Icon(Icons.comment),
                    ),
                  ],
                )
              ]
            ],
          ),
        ),
      ),
    );
  }
}

The problem is when I try to zoom-in or zoom-out my InteractiveViewer, it usually not works in first try, and I need to try 5-6 times in different touch positions to work, it is very hard to use InteractiveViewer in SingleChildScrollView, but it works perfect without SingleChildScrollView, see the clip below:

enter image description here

Is there any solutions?

amir_a14
  • 1,478
  • 10
  • 15

2 Answers2

2

It seems that there is a fight between SingleChildScrollView and InteractiveViewer to take the touch action.

With the example of Instagram's scrolling mechanism, if we place two fingers on the post and try to scroll, the scrolling action will not be done and somehow the scrolling will be temporarily disabled. So if we can detect this two finger touch action:

thanks to: https://stackoverflow.com/a/72421013/14083299

we can disable the scroll and then zoom in/out.

Here is a sample code:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final List<String> images = [
    'assets/prof2.jpg',
    'assets/prof2.jpg',
    'assets/prof2.jpg'
  ];

  final events = [];
  bool canScroll = true;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: SingleChildScrollView(
          physics: canScroll
              ? const ScrollPhysics()
              : const NeverScrollableScrollPhysics(),
          child: Listener(
            onPointerDown: (event) {
              events.add(event.pointer);
              print("new event");
            },
            onPointerUp: (event) {
              events.clear();
              print("events cleared");
              setState(() {
                canScroll = true;
              });
            },
            onPointerMove: (event) {
              if (events.length == 2) {
                setState(() {
                  canScroll = false;
                });
                //   int sensitivity = 8;
                //   if (event.delta.dy > sensitivity) {
                //     // code for two finger swipe up event

                //   } else if (event.delta.dy < -sensitivity) {
                //     // code for two finger swipe down event

                //   }
              }
            },
            child: Container(
              child: Column(
                children: [
                  for (var image in images) ...[
                    const SizedBox(
                        width: double.infinity,
                        child: Divider(
                          thickness: 5,
                        )),
                    Row(
                      children: [
                        Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: ClipOval(
                            child: CircleAvatar(
                              radius: 24,
                              child: Image.asset('assets/prof2.jpg'),
                            ),
                          ),
                        ),
                        const Text('User1'),
                      ],
                    ),
                    InteractiveViewer(
                        child: Image.asset(
                      image,
                      fit: BoxFit.fitWidth,
                    )),
                    Row(
                      children: const [
                        Padding(
                          padding: EdgeInsets.all(8.0),
                          child: Icon(Icons.favorite),
                        ),
                        Padding(
                          padding: EdgeInsets.all(8.0),
                          child: Icon(Icons.comment),
                        ),
                      ],
                    )
                  ]
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
samad karimi
  • 36
  • 1
  • 2
0

Thanks to @samad-karimi answer, I finally fix that with Listener Widget.

Example code:

        //First define _pointersCount=0 in your state class.
        Listener(
          onPointerDown: (_) => setState(() => _pointersCount++),
          onPointerUp: (_) => setState(() => _pointersCount--),
          child: ListView(
            physics: _pointersCount == 2 ? const NeverScrollableScrollPhysics() : null,
            children: [], //InteractiveViewer widgets here
        )),

This is optimized code from @samad-karimi code:

class MyApp2 extends StatefulWidget {
  MyApp2({Key? key}) : super(key: key);

  @override
  State<MyApp2> createState() => _MyApp2State();
}

class _MyApp2State extends State<MyApp2> {
  final List<String> images = [Images.IMG1, Images.IMG2, Images.IMG3];
  int _pointersCount = 0;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Listener(
          onPointerDown: (_) => setState(() => _pointersCount++),
          onPointerUp: (_) => setState(() => _pointersCount--),
          child: ListView(
            physics: _pointersCount == 2 ? const NeverScrollableScrollPhysics() : null,
            children: [
              for (var image in images) ...[
                const SizedBox(width: double.infinity, child: Divider(thickness: 5)),
                Row(
                  children: [
                    Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: ClipOval(
                        child: CircleAvatar(
                          radius: 24,
                          child: Image.asset(Images.PROFILE_IMAGE),
                        ),
                      ),
                    ),
                    const Text('User1'),
                  ],
                ),
                InteractiveViewer(child: Image.asset(image, fit: BoxFit.fitWidth)),
                Row(
                  children: const [
                    Padding(padding: EdgeInsets.all(8.0), child: Icon(Icons.favorite)),
                    Padding(padding: EdgeInsets.all(8.0), child: Icon(Icons.comment)),
                  ],
                )
              ]
            ],
          ),
        ),
      ),
    );
  }
}
amir_a14
  • 1,478
  • 10
  • 15