Search code examples
flutterdartnavigator

Navigator 2.0 Route Transition Bug


I am stuck with a bugged animation when I try to set a Navigator 2.0 on part of the screen. My App Layout simplified is:

MaterialApp -> Scaffold -> Row(NavigationBar, Navigator))

Inside the Navigator is the main content of the app, and subsequent routes should only be shown in this part of the screen as the navbar on the left should allow the user to always change the main route of the navigator.

However, first of all the Navigator on the right throws a shadow onto the navbar on the left (which can be "fixed" by setting the Route to fullscreenDialog:true)

When I push another MaterialPageRoute the animation is fine, as the new page slides in from the right (on an iOS device). However: when I push another route (which now lies ontop of a normal page, and not the fullscreen dialog anymore, the new page slides in from the ride, but the WHOLE app content gets transitioned as per MaterialPageRoute default, which buggs the nav bar which should be fixed on the left of the screen.)

TLDR: How can I set the MaterialPageRoute inside the Navigator 2.0 which only animates INSIDE the Navigator and not the root Navigator? this is killing me.

Example App:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Material App',
      home: HomeWidget(),
    );
  }
}

class HomeWidget extends StatelessWidget {
  const HomeWidget({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Material App Bar'),
        ),
        body: Row(
          children: [
            Flexible(flex: 1, child: Container(color: Colors.orange)),
            Expanded(
                flex: 9,
                child: Navigator(
                  onPopPage: (route, result) => true,
                  pages: [CupertinoPage(child: Page())],
                )),
          ],
        ));
  }
}

class Page extends StatelessWidget {
  const Page({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: TextButton(
          child: Text('Go Deeper'),
          onPressed: () => Navigator.of(context).push(MaterialPageRoute(
            builder: (context) => Page(),
          )),
        ),
      ),
    );
  }
}

Solution

  • The nested navigator is painting outside its bounds. To prevent this, you will need to place the navigator inside a ClipRect. This will also prevent shadows over the nav bar "for free".

                Expanded(
                    flex: 9,
                    child: ClipRect(
                      child: Navigator(
                        onPopPage: (route, result) => true,
                        pages: [CupertinoPage(child: Page())],
                      ),
                    )),