skip to Main Content

AIM: I wish to make my flutter app also on the web, hence, like most websites, I want it to have an AppBar that is always there no matter how many screens (routes) I push or where I navigate.

PROBLEM: However, when I do Navigator.push(), the AppBar disappears, since a new Scaffold is created with it’s own AppBar.

QUESTION: Is there any way to achieve a constant AppBar in my flutter app?

WHAT I TRIED: I tried using IndexedStack, which worked for my main screens. However, when I want to navigate from one of my main screens (which are in the indexed stack), this approach fails.

2

Answers


  1. return MaterialApp(
      builder: (BuildContext context, Widget? child) => Scaffold(
        appBar: AppBar(),
      ),
      home: MyHomePage(),
    );
    

    Edit

    sorry, the above doesn’t work so here is the solution:

    use MyPage as a template to any of your pages.

    the Hero widget is to keep the app bar at place in route transitions

    class MyPage extends StatelessWidget {
      const MyPage({super.key, required this.body});
      
      final Widget body;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Stack(
            fit: StackFit.expand,
            children: [
              body,
              Positioned(
                top: 0,
                left: 0,
                right: 0,
                child: MyAppBar(),
              ),
            ],
          ),
        );
      }
    }
    
    class MyAppBar extends StatelessWidget {
      const MyAppBar({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Hero(
          tag: 'appBar',
          child: child,// todo
        );
      }
    }
    
    Login or Signup to reply.
  2. You can use bottomNavigationBar parameter of the Scaffold() widget,
    or you can use another creative alternative like this:

    import 'package:flutter/material.dart';
    import 'package:go_router/go_router.dart';
    
    void main() {
    // To show deep linking in browser
    GoRouter.optionURLReflectsImperativeAPIs = true;
    runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
    const MyApp({super.key});
    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            title: 'DemoApp',
            routerConfig: appRouter,
            debugShowCheckedModeBanner: false);
    }
    }
    
    // --- Routes (go_router package)
    final appRouter = GoRouter(
    initialLocation: '/',
    routes: [
        GoRoute(path: '/', builder: (context, state) => const HomePage()),
        GoRoute(path: '/page1', builder: (context, state) => const Page1()),
        GoRoute(path: '/page2', builder: (context, state) => const Page2()),
    ],
    );
    
    // --- Home example
    class HomePage extends StatelessWidget {
    const HomePage({super.key});
    
    @override
    Widget build(BuildContext context) {
        return Scaffold(
        appBar: MyAppBar.build(context),
        body: BodyViewMockup.build('Home'),
        );
    }
    }
    
    final viewRoutes = <Widget>[_HomeView(), _Page1View(), _Page2View()];
    
    class Page1 extends StatelessWidget {
    const Page1({super.key});
    
    @override
    Widget build(BuildContext context) {
        return Scaffold(
        appBar: MyAppBar.build(context),
        body: BodyViewMockup.build('Page 1'),
        );
    }
    }
    
    class Page2 extends StatelessWidget {
    const Page2({super.key});
    
    @override
    Widget build(BuildContext context) {
        return Scaffold(
        appBar: MyAppBar.build(context),
        body: BodyViewMockup.build('Page 2'),
        );
    }
    }
    
    class _HomeView extends StatelessWidget {
    @override
    Widget build(BuildContext context) => BodyViewMockup.build('Home');
    }
    
    class _Page1View extends StatelessWidget {
    @override
    Widget build(BuildContext context) => BodyViewMockup.build('Page 1');
    }
    
    class _Page2View extends StatelessWidget {
    @override
    Widget build(BuildContext context) => BodyViewMockup.build('Page 2');
    }
    
    class BodyViewMockup {
    static Widget build(String title) {
        return ListView.builder(
            itemCount: 50,
            itemBuilder: (context, index) => Text('$title: item $index'));
    }
    }
    
    class MyAppBar {
    static AppBar build(BuildContext context) {
        final path = GoRouterState.of(context).fullPath ?? "";
        var title = "";
        switch (path) {
        case '/page1':
            title = 'Page 1';
            break;
        case '/page2':
            title = 'Page 2';
            break;
        default:
            title = 'Home';
        }
        return AppBar(title: Text(title), actions: [
        path == "/"
            ? Container()
            : IconButton(
                icon: const Icon(Icons.home_outlined),
                color: path == "/home/:page" ? Colors.grey : null,
                onPressed: () => path == "/home/:page" ? null : context.go('/')),
        IconButton(
            icon: const Icon(Icons.looks_one_outlined),
            color: path == "/page1" ? Colors.grey : null,
            onPressed: () => path == "/page1" ? null : context.push('/page1')),
        IconButton(
            icon: const Icon(Icons.looks_two_outlined),
            color: path == "/page2" ? Colors.grey : null,
            onPressed: () => path == "/page2" ? null : context.push('/page2'),
        ),
        ]);
    }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search