Repository: flutter
Issue: [GestureDetector][Scroll]: Zoom -> Scroll can't be achieved without lifting fingers. Scroll -> Zoom works as intended.
Labels: framework,f: scrolling,f: gestures,has reproducible steps,P2,found in release: 2.10,found in release: 2.13,team-framework,triaged-framework

See Videos.

In Flutter, you cannot scroll then zoom. In iOS, you can.

**Desired behavior A:** _Zoom->Scroll->Zoom->Scroll_ without needing to lift up fingers between gestures. This is how iOS and Android work. See videos. 

**Desired behavior B:** When a user _Zooms_, it is never confused for a _Scroll_. Currently, If the user does not precisely time their 2 fingers to touch at the same time, it gets confused for a _Scroll_. This is the bigger of the 2 issues imo. Fixing _Desired behavior A_ would implicitly fix this.

<details>
  <summary>flutter doctor -v</summary>
  [✓] Flutter (Channel stable, 2.10.3, on macOS 12.1 21C52 darwin-arm, locale en-US)
      • Flutter version 2.10.3 at /Volumes/User/MBP-Google-Drive/jamcorder/app/flutter
      • Upstream repository https://github.com/flutter/flutter.git
      • Framework revision 7e9793dee1 (3 weeks ago), 2022-03-02 11:23:12 -0600
      • Engine revision bd539267b4
      • Dart version 2.16.1
      • DevTools version 2.9.2
  
  [✗] Android toolchain - develop for Android devices
      ✗ Unable to locate Android SDK.
        Install Android Studio from: https://developer.android.com/studio/index.html
        On first launch it will assist you in installing the Android SDK components.
        (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
        If the Android SDK has been installed to a custom location, please use
        `flutter config --android-sdk` to update to that location.
  
  
  [✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
      • Xcode at /Applications/Xcode.app/Contents/Developer
      • CocoaPods version 1.11.2
  
  [✓] Chrome - develop for the web
      • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
  
  [!] Android Studio (not installed)
      • Android Studio not found; download from https://developer.android.com/studio/index.html
        (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
  
  [✓] VS Code (version 1.65.2)
      • VS Code at /Applications/Visual Studio Code.app/Contents
      • Flutter extension version 3.36.0
  
  [✓] Connected device (4 available)
      • ChipsiPhoneSE (mobile) • d574b0cb0afa5b927db881cc74c75201a031bb00 • ios            • iOS 13.4.1 17E262
      • ChipsiPhone (mobile)   • 00008101-000A0D1E3C90001E                • ios            • iOS 15.3.1 19D52
      • iPhone 13 (mobile)     • FF7C845F-340A-4611-BF36-E93C8E838C71     • ios            •
        com.apple.CoreSimulator.SimRuntime.iOS-15-2 (simulator)
      • Chrome (web)           • chrome                                   • web-javascript • Google Chrome 99.0.4844.83
      ! Error: ChipsiPhoneSE is busy: Fetching debug symbols for ChipsiPhoneSE. Xcode will continue when ChipsiPhoneSE is
        finished. (code -10)
      ! Error: ChipsiPhone is busy: Fetching debug symbols for ChipsiPhone. Xcode will continue when ChipsiPhone is
        finished. (code -10)
  
  [✓] HTTP Host Availability
      • All required HTTP hosts are available
  
  ! Doctor found issues in 2 categories.
</details>

## IOS
[Video IOS](https://user-images.githubusercontent.com/1863934/159809149-464705bb-de3f-4ac4-bf04-c5bfd7eb014d.mp4)
 
## Flutter
[Video Flutter](https://user-images.githubusercontent.com/1863934/159809140-2712a2fe-ed18-4a0f-929a-7f7bafcb63af.mp4)




<details>
<summary> Code: </summary>

```
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Scroll And Zoom',
      theme: CupertinoThemeData(primaryColor: Colors.white),
      home: 
        ZoomableList(),
    );
  }
}


class ZoomableList extends StatefulWidget {
  const ZoomableList({Key? key}) : super(key: key);

  @override
  State<ZoomableList> createState() => _ZoomableListState();
}

class _ZoomableListState extends State<ZoomableList> {

  final ScrollController _scrollController = ScrollController();

  double _itemExtentZoomBegin = 0;

  double _prevScale = 1.0;

  double _itemExtent = 100;

  @override
  void initState() {
    super.initState();
  }

  double scrollOffset(double tapY){
    return tapY + _scrollController.offset;
  }

  List<Widget> buildChildren(BuildContext context) {

    List<Widget> children = [];

    for(int i = 0; i < 30; i++){
      double hue = (i * 30) % 360;
      children.add(
        Container(
          height: _itemExtent,
          color: HSLColor.fromAHSL(1, hue, 0.5, 0.5).toColor(),
        )
      );
    }

    return children;
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onScaleStart: (details) {
        _itemExtentZoomBegin = _itemExtent;
        _prevScale = 1.0;
      },
      onScaleUpdate: (details) {
        setState(() {

          _itemExtent = _itemExtentZoomBegin * details.scale;

          // Zoom Into The Focal Point
          // Note: this is just a typical use case. Not necessary for repro
          double curFocal = scrollOffset(details.focalPoint.dy);
          double percentIncr = details.scale / _prevScale;
          double newFocal = curFocal * percentIncr;
          double focalDiff = newFocal - curFocal;
          double jumpTo = _scrollController.offset + focalDiff;
          _scrollController.jumpTo(jumpTo);

           _prevScale = details.scale;
        });
      },
      child: ListView(
        controller: _scrollController,
        itemExtent: _itemExtent,
        children: [
          ...buildChildren(context),
        ],
      ),
    );
  }
}

```
</details>