2

I have a MaterialApp in which it has an IndexedStack as its homePage, to use it for BottomBarNavigation. Now, in one of the "Tab"s, I want page transitions to be done like it is done in iOS.

Part of the trick can be done using CupertinoPageRoute in Navigator.push as follows:

Navigator.of(context, rootNavigator: true).push(CupertinoPageRoute<bool>(
      //fullscreenDialog: true,
      builder: (BuildContext context) => new DescriptionPage(),

    ));

this results the new page to slide from right as an iOS app. But, I also want the first page to be shifted to right with parallax, as it says in the CupertinoPageRoute's documentation:

The page also shifts to the left in parallax when another page enters to cover it.

this will be done if the first page itself is created via "Navigator.push(CupertinoPageRoute ...", but as I mentioned, my first page is one of the main pages of the application's home.

current transition style: the new page slides in from right, but the current page does not shift to left

as you can see, the current page does not shift to left. There might be a way to make the current page's widget to act as a widget built by a CupertinoPageRoute, so that the current page itself slides to left as the new page comes in.

Madhup Singh Yadav
  • 8,110
  • 7
  • 51
  • 84
Ramtin Didab
  • 21
  • 1
  • 3

2 Answers2

5

In the theme: parameter of MaterialApp, try this:

MaterialApp(
  theme: ThemeData( //or replace with your custom ThemeData.copywith()
    pageTransitionsTheme: PageTransitionsTheme(
      builders: {
        TargetPlatform.android: CupertinoPageTransitionsBuilder(),
        TargetPlatform.iOS: CupertinoPageTransitionsBuilder()
      }
    ),
  ),
)
royarg
  • 511
  • 5
  • 10
1

If you run the code below, you will see that First Tab is doing what you are seeing and second Tab is what you are expecting.

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CupertinoStoreHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class CupertinoStoreHomePage extends StatelessWidget {
  const CupertinoStoreHomePage({title});

  @override
  Widget build(BuildContext context) {
    return CupertinoTabScaffold(
      tabBar: CupertinoTabBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(CupertinoIcons.bell),
            title: Text('TAB1'),
          ),
          BottomNavigationBarItem(
            icon: Icon(CupertinoIcons.bell_solid),
            title: Text('TAB2'),
          ),
        ],
      ),
      tabBuilder: (context, index) {
        switch (index) {
          case 0:
            return CupertinoTabView(builder: (context) {
              return CupertinoPageScaffold(
                child: TAB1(),
              );
            });
          case 1:
            return CupertinoTabView(
              builder: (context) {
                return CupertinoPageScaffold(
                  child: TAB2(),
                );
              },
              routes: {
                '/screen': (ctx) => NextScreen(),
              },
            );

          default:
            return Container();
        }
      },
    );
  }
}

class TAB1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("TAB1"),
      ),
      body: Container(
        child: FlatButton(
          child: Text("Go To Next Screen"),
          onPressed: () => Navigator.of(context)
              .push(MaterialPageRoute(builder: (_) => NextScreen())),
        ),
      ),
    );
  }
}

class TAB2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("TAB2"),
      ),
      body: Container(
          child: FlatButton(
        child: Text("Go To Next Screen"),
        onPressed: () => Navigator.of(context).pushNamed("/screen"),
      )),
    );
  }
}

class NextScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      child: Scaffold(
        appBar: AppBar(
          title: Text("NextScreen"),
        ),
        body: Container(
          child: Text("NextScreen"),
        ),
      ),
    );
  }
}

When using Navigator.of(ctx).push the app tries to push new screen on root navigator, which in your case is tab bar but it fails to replace the tab bar, hence you see incomplete animation. But with second approach where you have defined route in relevant tab and use Push Named, the app uses navigator assigned to that tab and hence expected result.

Happy Coding!

Madhup Singh Yadav
  • 8,110
  • 7
  • 51
  • 84