Futter CupertinoNavigationBar very bad performance with root navigator

57 views Asked by At

For unknown reasons, I found out that the CupertinoNavigationBar causes huge lags and frame drops when transitioning between pages when the following conditions are met:

  • its parent, the CupertinoPageScaffold, is a page displayed within a CupertinoTabScaffold
  • the root navigator is used to push the page.

I was able to find that out when I commented out my CupertinoNavigationBar because then the app became butter smooth again.

Also, I find no issue if I am not using the root navigator (meaning the new page is displayed within the active tab), but this is not what I want to do.

Finally, in order to test out my theory, if there is no CupertinoTabScaffold, then I don't have the issue at all.

My issue only occurs on iPhone, even in profile mode.


The following is a minimum reproductible example:

import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'Flutter Demo',
      home: HomePage(),
    );
  }
}

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

  static const homePages = [
    HistoryPage(),
    MetricsPage(),
  ];

  @override
  Widget build(BuildContext context) {
    return CupertinoTabScaffold(
      tabBuilder: (_, index) => CupertinoTabView(
        builder: (_) => homePages[index],
      ),
      tabBar: CupertinoTabBar(
        items: const [
          BottomNavigationBarItem(
            label: 'History',
            icon: Icon(CupertinoIcons.square_list),
            activeIcon: Icon(CupertinoIcons.square_list_fill),
          ),
          BottomNavigationBarItem(
            label: 'Metrics',
            icon: Icon(CupertinoIcons.chart_bar_square),
            activeIcon: Icon(CupertinoIcons.chart_bar_square_fill),
          ),
        ],
      ),
      resizeToAvoidBottomInset: false,
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: const Text('History Tab'),
        trailing: CupertinoButton(
          padding: EdgeInsets.zero,
          child: const Icon(CupertinoIcons.add),
          onPressed: () {
            Navigator.of(context, rootNavigator: true)
                .push(CupertinoPageRoute(builder: (context) => const SimplePage()));
          },
        ),
      ),
      child: const Center(
        child: Text('This is the History Tab'),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return const CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text('Metrics Tab'),
      ),
      child: Center(
        child: Text('This is the Metrics Tab'),
      ),
    );
  }
}


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

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: const Text('Simple Page'),
        trailing: CupertinoButton(
          child: const Icon(CupertinoIcons.add),
          onPressed: () {
            Navigator.of(context, rootNavigator: true)
                .push(CupertinoPageRoute(builder: (context) => const SimplePage()));
          },
        ),
      ),
      child: const Center(
        child: Text('This is a simple page'),
      ),
    );
  }
}

Try to comment out the navigation bar and place the button in the child instead of the text and notice how differently it performs.

1

There are 1 answers

1
patrickg On BEST ANSWER

I encountered the same problem with this widget configuration with Flutter 3.16.8. Disabling the impeller rendering backend fixed the problem.

See:

https://docs.flutter.dev/perf/impeller