Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS App Freeze for ~0.5 second on Swipe Back Gesture #48225

Open
edwardez opened this issue Jan 6, 2020 · 44 comments · May be fixed by #140704
Open

iOS App Freeze for ~0.5 second on Swipe Back Gesture #48225

edwardez opened this issue Jan 6, 2020 · 44 comments · May be fixed by #140704
Labels
c: performance Relates to speed or footprint issues (see "perf:" labels) f: gestures flutter/packages/flutter/gestures repository. found in release: 3.7 Found to occur in 3.7 found in release: 3.9 Found to occur in 3.9 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list platform-ios iOS applications specifically team-ios Owned by iOS platform team triaged-ios Triaged by iOS platform team

Comments

@edwardez
Copy link

edwardez commented Jan 6, 2020

Steps to Reproduce

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(Root());

class Root extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: First());
  }
}

class First extends StatefulWidget {
  @override
  _FirstState createState() => _FirstState();
}

class _FirstState extends State<First> {
  var tappedTimes = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('First'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
              child: const Text('Go To Second'),
              onPressed: () {
                setState(() {
                  tappedTimes++;
                });
                Navigator.of(context).push(
                  CupertinoPageRoute(
                    builder: (BuildContext context) {
                      return Second();
                    },
                  ),
                );
              },
            ),
            InkWell(
              child: Text('I\'m tapped $tappedTimes times'),
            )
          ],
        ),
      ),
    );
  }
}

class Second extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Second'),
      ),
      body: Container(),
    );
  }
}

(Code is modified from #41024)

  1. Click 'Go To Second'
  2. Click go back button on the top left then quickly keep trying clicking 'Go To Second', 'Go To Second' button is clickable right away
  3. SWIPE back then quickly keep trying clicking 'Go To Second' again, notice that screen freezes for ~0.5 seconds

https://imgur.com/a/4Ubzrj4
Here is a demo, in the first few times I clicked go back button on the top left and as you can see, I'm able to click 'Go To Second' immediately after navigating back to the first screen, however starting "I'm tapped 5 times", there is a significantly delay before 'Go To Second' button is clickable since swipe back is used.

Target Platform: iPhone / iPad
Target OS version/browser: iOS13.3
Devices: Reproduced in multiple devices

Logs

flutter doctor                   
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale en-US)
 
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.3)
[!] Android Studio (version 3.4)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
[✓] IntelliJ IDEA Ultimate Edition (version 2019.3)
[!] VS Code (version 1.40.0)
    ✗ Flutter extension not installed; install from
      https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter
[✓] Connected device (1 available)

@VladyslavBondarenko VladyslavBondarenko added f: gestures flutter/packages/flutter/gestures repository. framework flutter/packages/flutter repository. See also f: labels. platform-ios iOS applications specifically labels Jan 6, 2020
@goderbauer goderbauer added the c: performance Relates to speed or footprint issues (see "perf:" labels) label Jan 6, 2020
@ldelafuente
Copy link

I'm facing the same problem. @edwardez Were you able to find a workaround or we should wait for an answer from the Flutter team?

@acoutts

This comment has been minimized.

@jmagman jmagman added this to Awaiting Triage in Mobile - iOS performance review Feb 25, 2020
@valsen

This comment has been minimized.

@iapicca
Copy link
Contributor

iapicca commented Jul 10, 2020

Hi @edwardez
I running this code with the latest master

logs
[✓] Flutter (Channel master, 1.20.0-8.0.pre.40, on Mac OS X 10.15.5 19F101, locale en-GB)
    • Flutter version 1.20.0-8.0.pre.40 at /Users/nevercode/development/flutter_master
    • Framework revision 6eaaf1650e (10 hours ago), 2020-07-09 18:04:37 -0700
    • Engine revision 9b3e3410f0
    • Dart version 2.9.0 (build 2.9.0-20.0.dev 06cb010247)


[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    • Android SDK at /Users/nevercode/Library/Android/sdk
    • Platform android-29, build-tools 29.0.2
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.5)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.5, Build version 11E608c
    • CocoaPods version 1.9.0

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.0)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 46.0.2
    • Dart plugin version 193.7361
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[✓] VS Code
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.12.1

[✓] Connected device (4 available)
    • iPhone 11 Pro Max (mobile) • D6967F45-CB0F-4D4E-AFD5-278816A21CAE • ios            • com.apple.CoreSimulator.SimRuntime.iOS-13-5 (simulator)
    • macOS (desktop)            • macos                                • darwin-x64     • Mac OS X 10.15.5 19F101
    • Web Server (web)           • web-server                           • web-javascript • Flutter Tools
    • Chrome (web)               • chrome                               • web-javascript • Google Chrome 83.0.4103.116

• No issues found!

I cannot reproduce the behaviour you are describing
are you still experiencing the issue with the latest stable version or above?
Thank you

@iapicca iapicca added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Jul 10, 2020
@palicka
Copy link

palicka commented Jul 14, 2020

I'm facing the same problem.
when I open new screen like this:

          Navigator.push(
              context,
              MaterialPageRoute/CupertinoPageRoute(
                builder: (context) => NewScreen(....),
              ));

and go back using swipe back gesture, UI is not clickable for like 0.5-1 second. I added back button ( Navigator.pop(context);) to new screen and when it's pressed, everything works as it should, so problem is in gesture navigation.

tested on simulator and real device - same behaviour

@iapicca
Copy link
Contributor

iapicca commented Jul 20, 2020

Hi @palicka @ldelafuente
are you experiencing the issue with the code sample above and the latest master?
If the code is not representative of the situation please provide a complete minimal reproducible code sample.
Thank you

@markusaksli-nc
Copy link
Member

Without additional information, we are unfortunately not sure how to resolve this issue.
We are therefore reluctantly going to close this bug for now.

Could everyone who still has this problem please file a new issue with the exact description of what happens, logs, and the output of flutter doctor -v.
All system setups can be slightly different, so it's always better to open new issues and reference related issues.

Thanks for your contribution.

Mobile - iOS performance review automation moved this from Awaiting triage to Engineer reviewed Aug 28, 2020
@markusaksli-nc markusaksli-nc removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Aug 28, 2020
@edwardez
Copy link
Author

edwardez commented Oct 6, 2020

I believe this issue is still there as of Flutter stable 1.22, minimal code/recorded video are all in the bug, not sure if I can provide any additional info.

But, if Flutter maintainers cannot reproduce this issue, probably it's just because I'm a little bit picky here.

@markusaksli-nc
Copy link
Member

The thread ended on a question for more information and it's standard practice to close if it isn't provided in 21 days (the bot should actually do this). I was able to reproduce this on the latest master 1.23.0-8.0.pre.185 with the original code you provided.

flutter doctor -v
[✓] Flutter (Channel master, 1.23.0-8.0.pre.185, on Mac OS X 10.15.7 19H2 x86_64, locale en-GB)
    • Flutter version 1.23.0-8.0.pre.185 at /Users/markus/development/flutter_master
    • Framework revision 6620f831e9 (7 hours ago), 2020-10-06 18:15:15 -0700
    • Engine revision 7e6191de07
    • Dart version 2.11.0 (build 2.11.0-186.0.dev)

 
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1)
    • Android SDK at /Users/markus/Library/Android/sdk
    • Platform android-30, build-tools 30.0.1
    • Java binary at: /Users/markus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/193.6626763/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 12.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.0.1, Build version 12A7300
    • CocoaPods version 1.9.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.0)
    • Android Studio at /Users/markus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/193.6626763/Android Studio.app/Contents
    • Flutter plugin version 48.1.2
    • Dart plugin version 193.7361
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[✓] Connected device (5 available)
    • Nevercode’s iPhone (mobile)         • b668e524315069f3db3661ac11ff1f66afafebdb • ios            • iOS 13.7
    • iPhone SE (2nd generation) (mobile) • B46F1F22-93B0-40C4-8DA7-1C9816E399F7     • ios            • com.apple.CoreSimulator.SimRuntime.iOS-14-0 (simulator)
    • macOS (desktop)                     • macos                                    • darwin-x64     • Mac OS X 10.15.7 19H2 x86_64
    • Web Server (web)                    • web-server                               • web-javascript • Flutter Tools
    • Chrome (web)                        • chrome                                   • web-javascript • Google Chrome 85.0.4183.121

• No issues found!

Not sure if this is intended as a failsafe of some sort for the gesture but it does happen. The steps can be simplified to:

  1. Spam the back button and Go To Second button as fast as you can
  2. Do the same but use the swipe back gesture instead of the button
  3. Notice the delay before the Go To Second button becomes interactable when swiping (Overlay is blocking?).

This is observable on both physical and iOS 14 simulator.

@markusaksli-nc markusaksli-nc reopened this Oct 7, 2020
@markusaksli-nc markusaksli-nc added found in release: 1.23 Found to occur in 1.23 has reproducible steps The issue has been confirmed reproducible and is ready to work on labels Oct 7, 2020
@bot509
Copy link

bot509 commented Dec 28, 2020

I'm facing the same problem on all of my 10+ apps.

flutter doctor -v
[✓] Flutter (Channel stable, 1.22.4, on macOS 11.0.1 20B29 darwin-x64, locale
    zh-Hans-CN)
    • Flutter version 1.22.4 at /Users/xxx/Git/flutter
    • Framework revision 1aafb3a8b9 (6 周前), 2020-11-13 09:59:28 -0800
    • Engine revision 2c956a31c0
    • Dart version 2.10.4
    • Pub download mirror https://pub.flutter-io.cn
    • Flutter download mirror https://storage.flutter-io.cn

 
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1)
    • Android SDK at /Users/xxx/Library/Android/sdk
    • Platform android-30, build-tools 30.0.1
    • Java binary at: /Applications/Android
      Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build
      1.8.0_242-release-1644-b3-6915495)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 12.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.2, Build version 12B45b
    • CocoaPods version 1.9.3

[!] Android Studio (version 4.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • Java version OpenJDK Runtime Environment (build
      1.8.0_242-release-1644-b3-6915495)

[✓] VS Code (version 1.52.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.18.0

[✓] Connected device (1 available)
    • iPhone 12 Pro Max (mobile) • 3E52F637-4634-45EA-B5DD-AFF90FC4B437 • ios •
      com.apple.CoreSimulator.SimRuntime.iOS-14-2 (simulator)

! Doctor found issues in 1 category.

@BazinC
Copy link

BazinC commented Jan 6, 2021

Any updates on this @markusaksli-nc ?
The issue was filled one year ago and nothing changed :(

Has anyone found a track or a workaround ? :)

@joshoconnor89
Copy link

I got a 500 point bounty on this:
https://stackoverflow.com/questions/65599653/ios-app-freeze-for-0-5-second-on-swipe-back-gesture-flutter-dart

if anyone is interested in racking up some points :)

@rickimaru18
Copy link
Contributor

rickimaru18 commented Jan 11, 2021

I tried investigating this issue using the sample code provided by @edwardez and found out that this is due to...

File: routes.dart
Class: _ModalScopeState
Function: build(...)
Lines:

AnimatedBuilder(
    // !!!!!!!!!!!!!!!!!!!!!!!!! userGestureInProgressNotifier becomes true
    animation: widget.route.navigator?.userGestureInProgressNotifier ?? ValueNotifier<bool>(false),
    builder: (BuildContext context, Widget child) {
        final bool ignoreEvents = _shouldIgnoreFocusRequest;
        focusScopeNode.canRequestFocus = !ignoreEvents;
        return IgnorePointer(
            ignoring: false,//ignoreEvents,  // <<<<<<<<<<<<<< Tried setting it to FALSE, resolves the issue.
            child: child,
        );
    },
    child: child,
),

Setting the IgnorePointer's ignoring property to false retains the First screen's animation and resolves the issue.

When I tried setting the userGestureInProgressNotifier to always return to false, and reverting my changes in IgnorePointer...

File: navigator.dart
Function: set _userGesturesInProgress
Lines:

set _userGesturesInProgress(int value) {
    _userGesturesInProgressCount = value;
    //userGestureInProgressNotifier.value = _userGesturesInProgress > 0; // <<<<<< Commented
}

This also resolves the issue but there's no animation for the First screen. (same as pressing back button in AppBar).

My Flutter doctor...

[✓] Flutter (Channel stable, 1.22.5, on macOS 11.1 20C69 darwin-x64, locale en-US)
    • Flutter version 1.22.5 at /Users/rickkystiannelim/Documents/sdk/flutter
    • Framework revision 7891006299 (5 weeks ago), 2020-12-10 11:54:40 -0800
    • Engine revision ae90085a84
    • Dart version 2.10.4

 
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at /Users/rickkystiannelim/Library/Android/sdk
    • Platform android-30, build-tools 30.0.2
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 12.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.2, Build version 12B45b
    • CocoaPods version 1.9.3

[!] Android Studio (version 4.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)

[✓] VS Code (version 1.52.1)         // <<<<<<<<<<<<<< IDE used
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.18.1

 
[✓] Connected device (1 available)                    
    • ASUS Z012DA (mobile) • G8AZCY00Z1714K5 • android-arm64 • Android 8.0.0 (API 26) // <<<<<< Device used

@xBugzilla
Copy link

xBugzilla commented Dec 30, 2021

Having this issue too in iOS in every screen.

Is there any news on this? Anyone found a solution/workaround?

@v6s7dn
Copy link

v6s7dn commented Feb 16, 2022

Is there any way to fix it now?

@toda-bps
Copy link

I found a hack 😏

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

@immutable
class CustomNavigator extends Navigator {
  const CustomNavigator({
    Key? key,
    List<Page<dynamic>> pages = const <Page<dynamic>>[],
    PopPageCallback? onPopPage,
    TransitionDelegate<dynamic> transitionDelegate =
        const DefaultTransitionDelegate<dynamic>(),
    String? initialRoute,
    RouteFactory? onGenerateRoute,
    RouteFactory? onUnknownRoute,
    List<NavigatorObserver> observers = const <NavigatorObserver>[],
    String? restorationScopeId,
    RouteListFactory onGenerateInitialRoutes =
        Navigator.defaultGenerateInitialRoutes,
    bool reportsRouteUpdateToEngine = false,
    bool requestFocus = true,
  }) : super(
          key: key,
          pages: pages,
          onPopPage: onPopPage,
          transitionDelegate: transitionDelegate,
          initialRoute: initialRoute,
          onGenerateRoute: onGenerateRoute,
          onUnknownRoute: onUnknownRoute,
          observers: observers,
          restorationScopeId: restorationScopeId,
          onGenerateInitialRoutes: onGenerateInitialRoutes,
          reportsRouteUpdateToEngine: reportsRouteUpdateToEngine,
          requestFocus: requestFocus,
        );

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

class CustomNavigatorState extends NavigatorState {
  bool _originalTimingGestureInProgress = false;
  bool get originalTimingGestureInProgress => _originalTimingGestureInProgress;

  bool _gestureInProgress = false;

  @override
  bool get userGestureInProgress => _gestureInProgress;

  @override
  void didStartUserGesture() {
    _gestureInProgress = true;
    _originalTimingGestureInProgress = true;
    super.didStartUserGesture();
  }

  @override
  void didStopUserGesture() {
    _gestureInProgress = false;
    _originalTimingGestureInProgress = false;
    super.didStopUserGesture();
  }

  void _handlePointerEnd() => _gestureInProgress = false;

  @override
  Widget build(BuildContext context) {
    final child = super.build(context);

    return Listener(
      onPointerUp: (event) => _handlePointerEnd(),
      onPointerCancel: (event) => _handlePointerEnd(),
      child: child,
    );
  }
}

@immutable
class CustomPageTransitionsTheme extends PageTransitionsTheme {
  const CustomPageTransitionsTheme();

  static const builder = CupertinoPageTransitionsBuilder();

  @override
  Widget buildTransitions<T>(
    PageRoute<T> route,
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
    Widget child,
  ) {
    final originalPageTransition = builder.buildTransitions<T>(
      route,
      context,
      animation,
      secondaryAnimation,
      child,
    );

    final linearTransition = (route.navigator! as CustomNavigatorState)
        .originalTimingGestureInProgress;

    if (route.fullscreenDialog) {
      return CupertinoFullscreenDialogTransition(
        primaryRouteAnimation: animation,
        secondaryRouteAnimation: secondaryAnimation,
        linearTransition: linearTransition,
        child: child,
      );
    } else {
      return CupertinoPageTransition(
        primaryRouteAnimation: animation,
        secondaryRouteAnimation: secondaryAnimation,
        linearTransition: linearTransition,
        child: (originalPageTransition as CupertinoPageTransition).child,
      );
    }
  }
}

@immutable
class AppRoot extends StatelessWidget {
  const AppRoot({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        pageTransitionsTheme: const CustomPageTransitionsTheme(),
      ),
      home: const SamplePage(),
      builder: (context, child) {
        final navigator = child! as Navigator;

        return CustomNavigator(
          key: navigator.key,
          pages: navigator.pages,
          onPopPage: navigator.onPopPage,
          transitionDelegate: navigator.transitionDelegate,
          initialRoute: navigator.initialRoute,
          onGenerateRoute: navigator.onGenerateRoute,
          onUnknownRoute: navigator.onUnknownRoute,
          observers: navigator.observers,
          restorationScopeId: navigator.restorationScopeId,
          onGenerateInitialRoutes: navigator.onGenerateInitialRoutes,
          reportsRouteUpdateToEngine: navigator.reportsRouteUpdateToEngine,
          requestFocus: navigator.requestFocus,
        );
      },
    );
  }
}

@immutable
class SamplePage extends StatelessWidget {
  const SamplePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Pop gesture hack sample')),
      body: ListView.builder(
        itemBuilder: (context, index) {
          return ListTile(
            title: Text('$index'),
            subtitle: const Text('Tap to push page'),
            onTap: () {
              Navigator.push<void>(
                context,
                MaterialPageRoute(builder: (context) => const SamplePage()),
              );
            },
          );
        },
      ),
    );
  }
}

@mariosutalo
Copy link

When will this be fixed it is really frustrating, it breaks user experience on IOS, user mostly use swipe back gesture to go to previous screen. this also happens when using Dismissible.

@toda-bps
Copy link

toda-bps commented May 21, 2022

Sadly, my hack became ineffective after #95757

@xiakexiaoyi
Copy link

VID_20220525_100411.mp4

@Mahdi2565
Copy link

I have same problem in flutter 3
Is there any solution?

@mariosutalo
Copy link

mariosutalo commented Nov 9, 2022

@willlockwood are there any news on this fix, I see this issue on flutter 3.x.x also. This issue really affects user experience on IOS, users perceive app as not responsive when they swipe back, this is bigger issue than IOS jank.

@mikearagao
Copy link

Just came accross this issue when developing the very basics of our new app, and it's really not ideal in terms of user experience. A simple app that should have no performance issues just feels like it's been badly built.

Is there any update on creative ways around it?

@HyShai
Copy link

HyShai commented Nov 23, 2022

It's a quite painful UX issue; 'swipe to navigate back to a list ' is ubiquitous user behavior, it's not like this is some edge case that's been overlooked.

This issue has been open for nearly 3 years, so I have no expectation that it will ever be fixed. Unfortunately, due to this, my team will likely need to move to a different stack for our upcoming project.

@mariosutalo
Copy link

It's a quite painful UX issue; 'swipe to navigate back to a list ' is ubiquitous user behavior, it's not like this is some edge case that's been overlooked.

This issue has been open for nearly 3 years, so I have no expectation that it will ever be fixed. Unfortunately, due to this, my team will likely need to move to a different stack for our upcoming project.

I think they don't look at these old issues, maybe open a new issue then they will a least have to reply.

@goderbauer goderbauer added the P2 Important issues not at the top of the work list label Nov 29, 2022
@codegangpk
Copy link

@toda-bps you're a life saver! thank god!! Amazing job on the hack!

I'm a iOS developer of 5+ years experience that started building a production app with Flutter. We're launching our startup app in a couple of weeks.

This 0.5 freezing behavior that occurs after the swipe back gestures on iOS is still here. I confirm.
This behavior is unacceptable for a standard iOS app, and it makes my app look very amateur. I think the widget that pushed the new widget into display, is disabled of its touch gesture recognizers until the swipe back gesture is completely finished on the new widget that was push on. And there looks like it takes a mere 0.5 seconds longer for the widget underneath to regain its touch functionality. In standard iOS, the gesture is restored right away as the ViewController underneath is visible again.

I hope the flutter devs fix this soon! It looks like the issue has been here for 3+ years. I almost considered switching to React Native😭 Other than that, I really enjoy Flutter and it's potential! But in the meanwhile, the hack works perfectly! even with the GetX library's navigation!
Please keep the hack working until the issue is fixed!

Big thanks!

@Valent1
Copy link

Valent1 commented Dec 28, 2022

Same issue happens to me with both XS Max and 11Pro on iOS 16.2.

`flutter doctor -v
[✓] Flutter (Channel stable, 3.3.10, on macOS 13.1 22C65 darwin-x64, locale
en-US)
• Flutter version 3.3.10 on channel stable at
/Users/valentino/Flutter/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 135454a (13 days ago), 2022-12-15 07:36:55 -0800
• Engine revision 3316dd8728
• Dart version 2.18.6
• DevTools version 2.15.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
• Android SDK at /Users/valentino/Library/Android/sdk
• Platform android-33, build-tools 33.0.0
• Java binary at: /Applications/Android
Studio.app/Contents/jre/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build
11.0.13+0-b1751.21-8125866)
• All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 14C18
• CocoaPods version 1.11.3

[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.3)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build
11.0.13+0-b1751.21-8125866)

[✓] Connected device (4 available)
• Pixel 6 Pro (mobile) • 1C141FDEE005NN • android-arm64 •
Android 13 (API 33)
• iPhone XS Max (mobile) • 00008020-000130A82600013A • ios • iOS
16.2 20C65
• macOS (desktop) • macos • darwin-x64 •
macOS 13.1 22C65 darwin-x64
• Chrome (web) • chrome • web-javascript •
Google Chrome 108.0.5359.124

[✓] HTTP Host Availability
• All required HTTP hosts are available

• No issues found!
`

@scottandrewzip
Copy link

The hack doesn't seem to work anymore. The child is no longer a navigator but a FocusScope. Anyone have a solution for replacing the navigator to fix this problem?

@toda-bps
Copy link

toda-bps commented Feb 10, 2023

@scottandrewzip I found that FocusScope's child is the Navigator.

I updated the hack: Tested with 3.3.10, 3.7.3 and 3.8.0-9.0.pre.20(001c495) which is the latest at the moment.

import 'dart:async';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

@immutable
class CustomNavigator extends Navigator {
  const CustomNavigator({
    super.key,
    super.pages,
    super.onPopPage,
    super.initialRoute,
    super.onGenerateInitialRoutes,
    super.onGenerateRoute,
    super.onUnknownRoute,
    super.transitionDelegate,
    super.reportsRouteUpdateToEngine,
    // >= 3.7.0
    // super.clipBehavior,
    super.observers,
    super.requestFocus,
    super.restorationScopeId,
  });

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

class CustomNavigatorState extends NavigatorState {
  bool _originalTimingGestureInProgress = false;
  bool get originalTimingGestureInProgress => _originalTimingGestureInProgress;

  bool _gestureInProgress = false;

  @override
  bool get userGestureInProgress => _gestureInProgress;

  @override
  void didStartUserGesture() {
    _gestureInProgress = true;
    _originalTimingGestureInProgress = true;
    super.didStartUserGesture();
  }

  @override
  void didStopUserGesture() {
    _gestureInProgress = false;
    _originalTimingGestureInProgress = false;
    super.didStopUserGesture();
  }

  void _handlePointerEnd() => _gestureInProgress = false;

  @override
  Widget build(BuildContext context) {
    final child = super.build(context);

    return Listener(
      onPointerUp: (event) => _handlePointerEnd(),
      onPointerCancel: (event) => _handlePointerEnd(),
      child: child,
    );
  }
}

@immutable
class CustomPageTransitionsTheme extends PageTransitionsTheme {
  const CustomPageTransitionsTheme();

  static const _builder = CupertinoPageTransitionsBuilder();

  @override
  Widget buildTransitions<T>(
    PageRoute<T> route,
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
    Widget child,
  ) {
    final originalPageTransition = _builder.buildTransitions<T>(
      route,
      context,
      animation,
      secondaryAnimation,
      child,
    );

    final navigator = route.navigator;
    if (navigator is! CustomNavigatorState) {
      return originalPageTransition;
    }

    final linearTransition = navigator.originalTimingGestureInProgress;

    if (route.fullscreenDialog) {
      return CupertinoFullscreenDialogTransition(
        primaryRouteAnimation: animation,
        secondaryRouteAnimation: secondaryAnimation,
        linearTransition: linearTransition,
        child: child,
      );
    } else {
      return CupertinoPageTransition(
        primaryRouteAnimation: animation,
        secondaryRouteAnimation: secondaryAnimation,
        linearTransition: linearTransition,
        child: (originalPageTransition as CupertinoPageTransition).child,
      );
    }
  }
}

@immutable
class AppRoot extends StatelessWidget {
  const AppRoot({super.key});

  Navigator _findNavigator(dynamic child) {
    if (child is Navigator) {
      return child;
    }
    // ignore: avoid_dynamic_calls
    return _findNavigator(child.child);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        pageTransitionsTheme: const CustomPageTransitionsTheme(),
      ),
      home: const SamplePage(),
      builder: (context, child) {
        final navigator = _findNavigator(child);

        return CustomNavigator(
          key: navigator.key,
          pages: navigator.pages,
          onPopPage: navigator.onPopPage,
          initialRoute: navigator.initialRoute,
          onGenerateInitialRoutes: navigator.onGenerateInitialRoutes,
          onGenerateRoute: navigator.onGenerateRoute,
          onUnknownRoute: navigator.onUnknownRoute,
          transitionDelegate: navigator.transitionDelegate,
          reportsRouteUpdateToEngine: navigator.reportsRouteUpdateToEngine,
          // >= 3.7.0
          // clipBehavior: navigator.clipBehavior,
          observers: navigator.observers,
          requestFocus: navigator.requestFocus,
          restorationScopeId: navigator.restorationScopeId,
        );
      },
    );
  }
}

@immutable
class SamplePage extends StatelessWidget {
  const SamplePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Pop gesture hack sample')),
      body: ListView.builder(
        itemBuilder: (context, index) {
          return ListTile(
            title: Text('$index'),
            subtitle: const Text('Tap to push page'),
            onTap: () {
              unawaited(
                Navigator.push<void>(
                  context,
                  MaterialPageRoute(builder: (context) => const SamplePage()),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

@toda-bps
Copy link

toda-bps commented Feb 10, 2023

Another example: using go_router with ShellRoute.

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

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

@immutable
class CustomNavigator extends Navigator {
  const CustomNavigator({
    super.key,
    super.pages,
    super.onPopPage,
    super.initialRoute,
    super.onGenerateInitialRoutes,
    super.onGenerateRoute,
    super.onUnknownRoute,
    super.transitionDelegate,
    super.reportsRouteUpdateToEngine,
    // >= 3.7.0
    // super.clipBehavior,
    super.observers,
    super.requestFocus,
    super.restorationScopeId,
  });

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

class CustomNavigatorState extends NavigatorState {
  bool _originalTimingGestureInProgress = false;
  bool get originalTimingGestureInProgress => _originalTimingGestureInProgress;

  bool _gestureInProgress = false;

  @override
  bool get userGestureInProgress => _gestureInProgress;

  @override
  void didStartUserGesture() {
    _gestureInProgress = true;
    _originalTimingGestureInProgress = true;
    super.didStartUserGesture();
  }

  @override
  void didStopUserGesture() {
    _gestureInProgress = false;
    _originalTimingGestureInProgress = false;
    super.didStopUserGesture();
  }

  void _handlePointerEnd() => _gestureInProgress = false;

  @override
  Widget build(BuildContext context) {
    final child = super.build(context);

    return Listener(
      onPointerUp: (event) => _handlePointerEnd(),
      onPointerCancel: (event) => _handlePointerEnd(),
      child: child,
    );
  }
}

@immutable
class CustomPageTransitionsTheme extends PageTransitionsTheme {
  const CustomPageTransitionsTheme();

  static const _builder = CupertinoPageTransitionsBuilder();

  @override
  Widget buildTransitions<T>(
    PageRoute<T> route,
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
    Widget child,
  ) {
    final originalPageTransition = _builder.buildTransitions<T>(
      route,
      context,
      animation,
      secondaryAnimation,
      child,
    );

    final navigator = route.navigator;
    if (navigator is! CustomNavigatorState) {
      return originalPageTransition;
    }

    final linearTransition = navigator.originalTimingGestureInProgress;

    if (route.fullscreenDialog) {
      return CupertinoFullscreenDialogTransition(
        primaryRouteAnimation: animation,
        secondaryRouteAnimation: secondaryAnimation,
        linearTransition: linearTransition,
        child: child,
      );
    } else {
      return CupertinoPageTransition(
        primaryRouteAnimation: animation,
        secondaryRouteAnimation: secondaryAnimation,
        linearTransition: linearTransition,
        child: (originalPageTransition as CupertinoPageTransition).child,
      );
    }
  }
}

Navigator _findNavigator(dynamic child) {
  if (child is Navigator) {
    return child;
  }
  // ignore: avoid_dynamic_calls
  return _findNavigator(child.child);
}

final _routes = GoRouter(
  routes: [
    ShellRoute(
      builder: (context, state, child) {
        final navigator = _findNavigator(child);

        return CustomNavigator(
          key: navigator.key,
          pages: navigator.pages,
          onPopPage: navigator.onPopPage,
          initialRoute: navigator.initialRoute,
          onGenerateInitialRoutes: navigator.onGenerateInitialRoutes,
          onGenerateRoute: navigator.onGenerateRoute,
          onUnknownRoute: navigator.onUnknownRoute,
          transitionDelegate: navigator.transitionDelegate,
          reportsRouteUpdateToEngine: navigator.reportsRouteUpdateToEngine,
          // >= 3.7.0
          // clipBehavior: navigator.clipBehavior,
          observers: navigator.observers,
          requestFocus: navigator.requestFocus,
          restorationScopeId: navigator.restorationScopeId,
        );
      },
      routes: [
        GoRoute(
          path: '/',
          builder: (context, state) => const RootPage(),
          routes: [
            GoRoute(
              path: 'second',
              builder: (context, state) => const SecondPage(),
            )
          ],
        ),
      ],
    )
  ],
);

@immutable
class AppRoot extends StatelessWidget {
  const AppRoot({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      theme: ThemeData(
        pageTransitionsTheme: const CustomPageTransitionsTheme(),
      ),
      routerConfig: _routes,
    );
  }
}

@immutable
class RootPage extends StatelessWidget {
  const RootPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'Pop gesture hack sample (GoRouter)',
        ),
      ),
      body: ListView.builder(
        itemBuilder: (context, index) {
          return ListTile(
            title: Text('$index'),
            subtitle: const Text('Tap to push page'),
            onTap: () => GoRouter.of(context).push('/second'),
          );
        },
      ),
    );
  }
}

@immutable
class SecondPage extends StatelessWidget {
  const SecondPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'Pop gesture hack sample (GoRouter)',
        ),
      ),
      body: const Center(
        child: Text('Second page'),
      ),
    );
  }
}

@danagbemava-nc
Copy link
Member

Reproduces on the latest versions of flutter.

Steps to reproduce

  • Run the code sample below
  • Tap the Go to Second button to navigate to the next page
  • Swipe back to the initial page and immediately try to tap the Go to Second button
updated sample
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: First());
  }
}

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

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

class _FirstState extends State<First> {
  var tappedTimes = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('First'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              child: const Text('Go To Second'),
              onPressed: () {
                setState(() {
                  tappedTimes++;
                });
                Navigator.of(context).push(
                  CupertinoPageRoute(
                    builder: (BuildContext context) {
                      return const Second();
                    },
                  ),
                );
              },
            ),
            InkWell(
              child: Text('I\'m tapped $tappedTimes times'),
            )
          ],
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Second'),
      ),
      body: Container(),
    );
  }
}
flutter doctor -v
[✓] Flutter (Channel stable, 3.7.7, on macOS 13.2.1 22D68 darwin-arm64, locale en-GB)
    • Flutter version 3.7.7 on channel stable at /Users/nexus/dev/sdks/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 2ad6cd72c0 (13 days ago), 2023-03-08 09:41:59 -0800
    • Engine revision 1837b5be5f
    • Dart version 2.19.4
    • DevTools version 2.20.1

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9619390/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14C18
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] Android Studio (version 2022.1)
    • Android Studio at /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] Android Studio (version 2022.1)
    • Android Studio at /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9619390/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] IntelliJ IDEA Community Edition (version 2022.3.3)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 72.1.4
    • Dart plugin version 223.8888

[✓] VS Code (version 1.76.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.60.0

[✓] Connected device (4 available)
    • M2007J20CG (mobile) • adb-5dd3be00-17AYzd._adb-tls-connect._tcp. • android-arm64  • Android 12 (API 31)
    • Nexus (mobile)      • 00008020-001875E83A38002E                  • ios            • iOS 16.3.1 20D67
    • macOS (desktop)     • macos                                      • darwin-arm64   • macOS 13.2.1 22D68 darwin-arm64
    • Chrome (web)        • chrome                                     • web-javascript • Google Chrome 111.0.5563.64

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!
[!] Flutter (Channel master, 3.9.0-11.0.pre.7, on macOS 13.2.1 22D68 darwin-arm64, locale en-GB)
    • Flutter version 3.9.0-11.0.pre.7 on channel master at /Users/nexus/dev/sdks/flutters
    ! Warning: `flutter` on your path resolves to /Users/nexus/dev/sdks/flutter/bin/flutter, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutters. Consider adding /Users/nexus/dev/sdks/flutters/bin to the front of your path.
    ! Warning: `dart` on your path resolves to /Users/nexus/dev/sdks/flutter/bin/dart, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutters. Consider adding /Users/nexus/dev/sdks/flutters/bin to the front of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 1cd55934f9 (27 hours ago), 2023-03-20 02:26:27 -0400
    • Engine revision 19a5f61ff7
    • Dart version 3.0.0 (build 3.0.0-339.0.dev)
    • DevTools version 2.22.2
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9619390/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14C18
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] Android Studio (version 2022.1)
    • Android Studio at /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] Android Studio (version 2022.1)
    • Android Studio at /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9619390/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] IntelliJ IDEA Community Edition (version 2022.3.3)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 72.1.4
    • Dart plugin version 223.8888

[✓] VS Code (version 1.76.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.60.0

[✓] Connected device (4 available)
    • M2007J20CG (mobile) • adb-5dd3be00-17AYzd._adb-tls-connect._tcp. • android-arm64  • Android 12 (API 31)
    • Nexus (mobile)      • 00008020-001875E83A38002E                  • ios            • iOS 16.3.1 20D67
    • macOS (desktop)     • macos                                      • darwin-arm64   • macOS 13.2.1 22D68 darwin-arm64
    • Chrome (web)        • chrome                                     • web-javascript • Google Chrome 111.0.5563.64

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 1 category.

@danagbemava-nc danagbemava-nc added found in release: 3.7 Found to occur in 3.7 found in release: 3.9 Found to occur in 3.9 and removed found in release: 1.23 Found to occur in 1.23 labels Mar 21, 2023
@xBugzilla
Copy link

xBugzilla commented May 10, 2023

The issue can be experienced in this UI package demo (disclosure: not affiliated at all). It has Flutter embedded so you can see it in action.

If you push a new route and pop it with the iOS gesture of swiping on the left edge, the home route freezes for XYZms, even after the route animation is finished. The freeze can be seen in the hover effect button. Even if you hover the cursor quickly, the button does not have the hover effect until the freeze is over.

If you pop the route with the appBar leading Icon then the freeze does not happen.

Screen.Recording.2023-05-10.at.12.29.58.mov

@flutter-triage-bot flutter-triage-bot bot added multiteam-retriage-candidate team-ios Owned by iOS platform team triaged-ios Triaged by iOS platform team labels Jul 8, 2023
@wisnhusurya
Copy link

This issue also exists in go_router @chunhtai
Please help us :)

@toda-bps
Copy link

Unfortunately my ShellRoute hack no longer works with go_router v13 😞

The Navigator widget is now built deep inside go_router's own _CustomNavigator widget and cannot be replaced.

@toda-bps
Copy link

I found another way.

I copied the entire code of CupertinoRouteTransitionMixin including _CupertinoBackGestureController and made the following customizations.

  • _CupertinoBackGestureController
    • At dragEnd, call navigator.didStopUserGesture() to quickly enable touch on the underlying screen, regardless of whether it is animated or not.
  • _CustomCupertinoRouteTransitionMixin
    • Tracks the state of the Pop animation and uses it in conjunction with route.navigator!.userGestureInProgress to determine whether to use linearTransition.

https://gist.github.com/toda-bps/f0d99dc5e87be019dbd71ebdfb7da435

By creating a PageTransitionsTheme that uses a customized CupertinoRouteTransitionMixin, you can now quickly operate the screen below regardless of whether you use ShellRoute or even GoRouter.

However, this method is not ideal because it largely copies the code from the SDK, so it cannot keep up with Flutter updates, for example.

@chunhtai
Copy link
Contributor

cc @hangyujin since you fixed a similar issue in this area

@toda-bps it looks like you found a fix already, do you want to submit a pr :)

@toda-bps
Copy link

@chunhtai I've created a pull request: #140704.

But, I'm having trouble passing some checks that I don't think are relevant to this fix... Is LUCI not feeling well?

@FrazeColder
Copy link

@toda-bps thank you for your awesome work! What is the current status? Why are they not accepting your PR?

@eddyuan
Copy link

eddyuan commented Mar 20, 2024

Sadly the problem still persists even 4 years after the report.

@inset0

This comment was marked as off-topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: performance Relates to speed or footprint issues (see "perf:" labels) f: gestures flutter/packages/flutter/gestures repository. found in release: 3.7 Found to occur in 3.7 found in release: 3.9 Found to occur in 3.9 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list platform-ios iOS applications specifically team-ios Owned by iOS platform team triaged-ios Triaged by iOS platform team
Projects
Mobile - iOS performance review
  
Engineer reviewed
Development

Successfully merging a pull request may close this issue.