Skip to content

FadeForwardsPageTransition: while going back, incoming page is not interactive #168424

@justinmc

Description

@justinmc

Steps to reproduce

  1. Run an app with multiple routes that uses FadeForwardsPageTransition, such as the one given below.
  2. Navigate to a page with a back button.
  3. Press back.
  4. During the back transition, attempt to interact with the incoming page.

Expected results

The incoming page is interactive, in the same way that it is when navigating forward.

Actual results

The incoming page is not interactive. This is fairly noticeable because the duration of the transition is fairly long at 800ms.

If I hardcode the opacity to 1.0, this illustrates the problem. The route on top is blocking the button underneath.

Code sample

Code sample
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart' show timeDilation;

void main() {
  timeDilation = 1.0;
  runApp(const MainApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        brightness: Brightness.light,
        pageTransitionsTheme: const PageTransitionsTheme(
          builders: {
            TargetPlatform.android: FadeForwardsPageTransitionsBuilder(),
          },
        ),
      ),
      home: const FirstScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('First Screen'),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            ElevatedButton(
              onPressed: () {
                Navigator.of(context).push(
                  MaterialPageRoute(builder: (_) => const SecondScreen()),
                );
              },
              child: const Text('Go to Second Screen'),
            ),
          ],
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Theme(
      data: ThemeData(brightness: Brightness.light),
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Second Screen'),
        ),
        body: Center(
          child: PopScope(
            canPop: true,
            onPopInvoked: (bool didPop) {
              print('justin popinvoked $didPop');
            },
            child: Column(
              children: <Widget>[
                ElevatedButton(
                  onPressed: () {
                    Navigator.of(context).push(
                      MaterialPageRoute(builder: (_) => const ThirdScreen()),
                    );
                  },
                  child: const Text('Go to Third Screen'),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Theme(
      data: ThemeData(brightness: Brightness.dark),
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Third Screen'),
        ),
        body: Center(
          child: PopScope(
            canPop: true,
            onPopInvoked: (bool didPop) {
              print('justin popinvoked $didPop');
            },
            child: Column(
              children: <Widget>[
                ElevatedButton(
                  onPressed: () {
                    Navigator.of(context).push(
                      MaterialPageRoute(builder: (_) => const FourthScreen()),
                    );
                  },
                  child: const Text('Go to Fourth Screen'),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Theme(
      data: ThemeData(brightness: Brightness.dark),
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Fourth Screen'),
        ),
        body: Center(
          child: PopScope(
            canPop: true,
            onPopInvoked: (bool didPop) {
              print('justin popinvoked $didPop');
            },
            child: const Text('Hello, Predictive back!'),
          ),
        ),
      ),
    );
  }
}

Screenshots or Video

Actual: Can't interact until the transition is done (800ms)
screen-20250506-144109.mp4
Expected: Can interact immediately
screen-20250506-144329.mp4

Logs

Flutter Doctor output

Doctor output
[!] Flutter (Channel master, 3.32.0-1.0.pre.392, on Debian GNU/Linux rodete 6.12.17-1rodete2-amd64, locale en_US.UTF-8)
    ! Upstream repository [email protected]:justinmc/flutter.git is not a standard remote.
      Set environment variable "FLUTTER_GIT_URL" to [email protected]:justinmc/flutter.git to dismiss this error.
[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
[✓] Chrome - develop for the web
[✓] Linux toolchain - develop for Linux desktop
[✓] Android Studio (version 2023.3)
[✓] Connected device (3 available)
[✓] Network resources

! Doctor found issues in 1 category.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions