Scaffold#

Scaffold is a layout structure provided by the Material Design library that serves as the basic visual framework for building the UI of an app screen.

Scaffold(

  1. appBar: The top app bar of the scaffold.

  2. body: The primary content of the scaffold.

  3. floatingActionButton: A button that floats above the body content.

  4. floatingActionButtonLocation: This controls where the floating action button is placed.

  5. floatingActionButtonAnimator: This controls the animation of the floating action button.

  6. persistentFooterButtons: A set of buttons that are always visible at the bottom.

  7. drawer: A drawer that slides in from the side for navigation.

  8. endDrawer: A drawer that slides in from the opposite side.

  9. bottomNavigationBar: A bar displayed at the bottom for navigation.

  10. bottomSheet: A persistent bottom sheet.

  11. backgroundColor: The background color of the scaffold.

  12. resizeToAvoidBottomInset: Whether the scaffold should adjust when the keyboard appears.

  13. primary: Whether this scaffold is the primary scaffold in the app.

  14. drawerScrimColor: The color of the scrim that is overlaid when a drawer is open.

  15. extendBody: Whether the body should extend behind the bottom navigation bar.

  16. extendBodyBehindAppBar: Whether the body should extend behind the app bar.

)

βœ…1.appBar:#

Here is a very simple Flutter program that shows what the appBar: parameter in Scaffold does.

It adds a bar at the top of the screen that can contain a title, icons, and actions.

βœ… Example: Using appBar: in Scaffold

import 'package:flutter/material.dart';

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

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

    @override
    Widget build(BuildContext context) {
        return MaterialApp(
            debugShowCheckedModeBanner: false,
            home: Scaffold(
                // βœ… appBar parameter
                appBar: AppBar(
                    title: const Text('My First AppBar'),
                    centerTitle: true,
                    backgroundColor: Colors.blue,
                ),

                body: const Center(
                    child: Text(
                        'Hello, World!',
                        style: TextStyle(fontSize: 24),
                    ),
                ),
            ),
        );
    }
}

What this program teaches you

Part

Meaning

Scaffold

appBar:

AppBar()

title:

centerTitle:

backgroundColor:

Main page layout

The top bar of the screen

Creates the top bar

Text shown in the bar

Centers the text

Changes bar color

When you run this app, you will see:

βœ… A blue bar at the top

βœ… Text β€œMy First AppBar” in the center

βœ… β€œHello, World!” in the middle of the screen

πŸ” Remove AppBar to see the difference

If you remove the appBar part, the top bar disappears:

Scaffold(
    body: Center(
        child: Text('No AppBar here'),
    ),
)

This shows the importance of the appBar: parameter inside Scaffold.


βœ…2.body:#

Here is a very simple Flutter program that explains the body: parameter in Scaffold.

The body is the main content area of your screen β€” everything you want to show in the middle of the page goes inside it.

βœ… Example: Using body: in Scaffold

import 'package:flutter/material.dart';

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

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

    @override
    Widget build(BuildContext context) {
        return MaterialApp(
            debugShowCheckedModeBanner: false,
            home: Scaffold(

                // βœ… App bar is optional
                appBar: AppBar(
                    title: const Text('Scaffold Body Example'),
                ),

                // βœ… This is the BODY parameter
                body: Center(
                    child: Text(
                        'This is the BODY of the Scaffold',
                        style: TextStyle(fontSize: 22),
                    ),
                ),
            ),
        );
    }
}

What this program teaches

Part

Meaning

Scaffold

body:

Center

Text

Main layout of the page

The main content area

Centers the content

Displays text inside the body

When you run this program, you will see:

βœ… AppBar at the top

βœ… Text in the center of the screen

βœ… That text is inside the body

This shows that everything inside the screen is placed using body:.

πŸ” Change Body to a Different Widget

Now change the body to a Container:

body: Container(
    color: Colors.orange,
    child: const Center(
        child: Text(
            'New Body Content',
            style: TextStyle(fontSize: 24, color: Colors.white),
        ),
    ),
),

Now the whole screen becomes orange.

This proves:

➑️ body controls the entire main screen area

πŸ”‘ Important Concept

In Scaffold:

Scaffold(
    appBar: ...
    body: ...      //← MAIN SCREEN CONTENT
)

The body: can contain ANY widget:

  • Text

  • Column

  • Row

  • ListView

  • Container

  • Stack

  • Image

  • Custom widget

βœ…3.floatingActionButton:#

Here is a very simple Flutter program that shows what the floatingActionButton: parameter in Scaffold does.

The floatingActionButton is the round button that floats at the bottom-right corner of the screen by default.

βœ… Simple Example: floatingActionButton in Scaffold

import 'package:flutter/material.dart';

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

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

    @override
    Widget build(BuildContext context) {
        return MaterialApp(
            debugShowCheckedModeBanner: false,
            home: Scaffold(
                appBar: AppBar(
                    title: const Text('Floating Button Example'),
                ),

                body: const Center(
                    child: Text(
                        'Tap the floating button!',
                        style: TextStyle(fontSize: 22),
                    ),
                ),

                // βœ… floatingActionButton parameter
                floatingActionButton: FloatingActionButton(
                    onPressed: () {
                        print("Floating button pressed!");
                    },
                    child: const Icon(Icons.add),
                ),
            ),
        );
    }
}

What this program teaches

Part

Meaning

floatingActionButton:

FloatingActionButton

onPressed

Icon(Icons.add)

Adds a floating button

The widget for the button

What happens when you tap it

The + sign on the button

When you run this app, you will see:

βœ… A round β€œ+” button at the bottom-right

βœ… When you tap it, a message prints in the console

βœ… The button floats ABOVE the body content

πŸ” Change the Button Position

You can move the button to the center bottom like this:

floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,

Full change:

floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,

Now the button is centered at the bottom.

πŸ”‘ Important Concept

The floatingActionButton is mainly used for:

βœ… Add

βœ… Create

βœ… Upload

βœ… New message

βœ… Scan

βœ… Quick actions

It is commonly used in apps like WhatsApp, Gmail, Maps.


βœ… Simple Example: floatingActionButton with MaterialApp.router()

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

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

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

    // βœ… Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(

            appBar: AppBar(
                title: const Text('FAB with MaterialApp.router'),
            ),

            body: const Center(
                child: Text(
                    'This page uses MaterialApp.router()',
                    style: TextStyle(fontSize: 20),
                ),
            ),

            // βœ… floatingActionButton parameter
            floatingActionButton: FloatingActionButton(
                onPressed: () {
                    print("Floating Action Button Pressed!");
                },
                child: const Icon(Icons.add),
            ),

            // βœ… Button position
            floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
        );
    }
}

Important: Add this to pubspec.yaml

Because this uses GoRouter, you must add this dependency:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Then run:

flutter pub get

What this program teaches

Part

Meaning

MaterialApp.router()

Used for navigation with Router API

routerConfig:

Controls all app routes

Scaffold

The page layout

floatingActionButton:

Floating button on the page

FloatingActionButtonLocation.endFloat

Bottom-right location

When you run it, you will see:

βœ… AppBar

βœ… A text message in the middle

βœ… A floating + button at bottom right

Press the button β†’ It prints a message in the console.


βœ…4.floatingActionButtonLocation:#

Here is a very simple Flutter program that shows how the floatingActionButtonLocation: parameter in Scaffold works, and it uses MaterialApp.router() exactly as you requested.

This example lets you see the position change clearly.

βœ… Simple Program: floatingActionButtonLocation with MaterialApp.router()

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

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

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

    // Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text('FAB Location Example'),
            ),

            body: const Center(
                child: Text(
                    'Look at the position of the button',
                    style: TextStyle(fontSize: 20),
                ),
            ),

            floatingActionButton: FloatingActionButton(
                onPressed: () {
                print("FAB clicked");
                },
                child: const Icon(Icons.navigation),
            ),

            // βœ… Change position using floatingActionButtonLocation
            floatingActionButtonLocation:
                FloatingActionButtonLocation.centerFloat,
        );
    }
}

What this program teaches

The important line is:

floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,

This moves the button to the BOTTOM CENTER of the screen instead of the default bottom-right.

Try these positions (just change ONE line)

Location Code

Button Position

FloatingActionButtonLocation.endFloat

Bottom Right (default)

FloatingActionButtonLocation.startFloat

Bottom Left

FloatingActionButtonLocation.centerFloat

Bottom Center

FloatingActionButtonLocation.endTop

Top Right

FloatingActionButtonLocation.centerTop

Top Center

Example change:

floatingActionButtonLocation: FloatingActionButtonLocation.endTop,

Now the button moves to the top-right corner.

Dependency Required

Don’t forget in pubspec.yaml:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Run:

flutter pub get

βœ…5.floatingActionButtonAnimator:#

Here is a very simple Flutter program that demonstrates the floatingActionButtonAnimator: parameter of Scaffold, using MaterialApp.router() as you requested.

This parameter controls how the Floating Action Button animates when it changes position (for example: from bottom-right to center).

To make the animation visible, I use a stateful page and a button tap to change location.

βœ… Simple Program: floatingActionButtonAnimator with MaterialApp.router()

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

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

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

    // Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

class HomePage extends StatefulWidget {
    const HomePage({super.key});

    @override
    State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
    // Toggle between two positions
    FloatingActionButtonLocation _location = FloatingActionButtonLocation.endFloat;

    void _changePosition() {
        setState(() {
        _location = _location == FloatingActionButtonLocation.endFloat
            ? FloatingActionButtonLocation.centerFloat
            : FloatingActionButtonLocation.endFloat;
        });
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text('FAB Animator Example'),
            ),

            body: const Center(
                child: Text(
                    'Tap the button to change its position',
                    style: TextStyle(fontSize: 18),
                ),
            ),

            floatingActionButton: FloatingActionButton(
                onPressed: _changePosition,
                child: const Icon(Icons.swap_horiz),
            ),

            // βœ… This changes the position
            floatingActionButtonLocation: _location,

            // βœ… This controls HOW it animates
            floatingActionButtonAnimator:
                FloatingActionButtonAnimator.scaling,
        );
    }
}

What this program teaches

The important new line is:

floatingActionButtonAnimator: FloatingActionButtonAnimator.scaling,

This means:

βœ… When the FAB moves, it scales (shrinks and grows) during the animation.

There are 2 built-in animators in Flutter:

Animator

Effect

FloatingActionButtonAnimator.scaling βœ…

Default scale animation

FloatingActionButtonAnimator.noAnimation

No animation

Try changing this line:

floatingActionButtonAnimator: FloatingActionButtonAnimator.noAnimation,

Now the button will jump instantly without smooth animation.

Why this is important

The floatingActionButtonAnimator is used when:

βœ… FAB position changes

βœ… Screen layout changes

βœ… Scaffold updates its geometry

βœ… You want smooth UI transitions

This is especially useful in professional apps with animated UI.

Dependency Reminder

In your pubspec.yaml:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Then run:

flutter pub get

βœ…6.persistentFooterButtons:#

Here is a very simple Flutter program that demonstrates the persistentFooterButtons: parameter in Scaffold, using MaterialApp.router() as you requested.

persistentFooterButtons creates fixed buttons at the bottom of the screen that stay visible even when the body scrolls.

βœ… Simple Program: persistentFooterButtons with MaterialApp.router()

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

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

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

    // Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text('Persistent Footer Example'),
            ),

            body: const Center(
                child: Text(
                    'Buttons below are fixed (persistent)',
                    style: TextStyle(fontSize: 18),
                ),
            ),

            // βœ… persistentFooterButtons
            persistentFooterButtons: [
                TextButton(
                    onPressed: () {
                        print("Cancel pressed");
                    },
                    child: const Text('Cancel'),
                ),

                ElevatedButton(
                    onPressed: () {
                        print("Save pressed");
                    },
                    child: const Text('Save'),
                ),
            ],
        );
    }
}

What this program teaches

Part

Meaning

persistentFooterButtons:

Creates fixed buttons at the bottom

TextButton

A simple flat button

ElevatedButton

A raised button

Position

Stays at the bottom of the screen

When you run the app, you will see:

βœ… Two buttons at the bottom of the screen

βœ… β€œCancel” and β€œSave”

βœ… They stay visible all the time

πŸ” Try adding more buttons

You can add more:

persistentFooterButtons: [
    IconButton(onPressed: () {}, icon: Icon(Icons.home)),
    IconButton(onPressed: () {}, icon: Icon(Icons.favorite)),
    IconButton(onPressed: () {}, icon: Icon(Icons.settings)),
],

They will stay in a horizontal row at the bottom.

Dependency Reminder

In pubspec.yaml:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Run:

flutter pub get

βœ…7.drawer:#

Here is a very simple Flutter program that demonstrates the drawer: parameter of Scaffold, using MaterialApp.router() exactly as you requested.

The drawer is the sliding menu that opens from the left side.

βœ… Simple Program: drawer with MaterialApp.router()

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

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

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

    // Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
            GoRoute(
                path: '/about',
                builder: (context, state) => const AboutPage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(

            appBar: AppBar(
                title: const Text('Drawer Example'),
            ),

            // βœ… Drawer parameter
            drawer: Drawer(
                child: ListView(
                    padding: EdgeInsets.zero,
                    children: [

                        const DrawerHeader(
                            decoration: BoxDecoration(color: Colors.blue),
                            child: Text(
                                'My Menu',
                                style: TextStyle(color: Colors.white, fontSize: 24),
                            ),
                        ),

                        ListTile(
                            leading: const Icon(Icons.home),
                            title: const Text('Home'),
                            onTap: () {
                                Navigator.pop(context); // close drawer
                            },
                        ),

                        ListTile(
                            leading: const Icon(Icons.info),
                            title: const Text('About'),
                            onTap: () {
                                Navigator.pop(context); // close drawer
                                context.go('/about');   // go to About page
                            },
                        ),
                    ],
                ),
            ),

            body: const Center(
                child: Text(
                'Swipe from left or tap the menu icon',
                style: TextStyle(fontSize: 18),
                ),
            ),
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text('About Page'),
            ),
            body: const Center(
                child: Text(
                    'You navigated using Drawer!',
                    style: TextStyle(fontSize: 20),
                ),
            ),
        );
    }
}

What this program teaches

Part

Meaning

drawer:

Adds a left-side sliding menu

Drawer()

The actual drawer widget

DrawerHeader

Top section of drawer

ListTile

Menu item inside drawer

context.go(β€˜/about’)

Go to another page

Navigator.pop(context)

Close the drawer

When you run this app:

βœ… You will see a menu icon (☰) in the AppBar

βœ… Tap it β†’ the drawer slides from the left

βœ… Tap About β†’ it opens a new page

Pubspec dependency (Important)

In pubspec.yaml, you must have:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Then:

flutter pub get

βœ…8.endDrawer:#

Here is a very simple Flutter program that demonstrates the endDrawer: parameter in Scaffold, using MaterialApp.router() exactly as you requested.

endDrawer is a drawer that slides from the RIGHT side of the screen (opposite of drawer, which comes from the left).

βœ… Simple Program: endDrawer with MaterialApp.router()

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

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

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

    // Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text('End Drawer Example'),

                // βœ… Button to open the END drawer (right side)
                actions: [
                    Builder(
                        builder: (context) => IconButton(
                            icon: const Icon(Icons.menu),
                            onPressed: () {
                                Scaffold.of(context).openEndDrawer();
                            },
                        ),
                    ),
                ],
            ),

            body: const Center(
                child: Text(
                    'Tap the menu icon on the RIGHT',
                    style: TextStyle(fontSize: 18),
                ),
            ),

            // βœ… endDrawer parameter (right-side drawer)
            endDrawer: Drawer(
                child: ListView(
                    padding: EdgeInsets.zero,
                    children: const [

                        DrawerHeader(
                            decoration: BoxDecoration(color: Colors.green),
                            child: Text(
                                'Right Menu',
                                style: TextStyle(color: Colors.white, fontSize: 24),
                            ),
                        ),

                        ListTile(
                            leading: Icon(Icons.settings),
                            title: Text('Settings'),
                        ),

                        ListTile(
                            leading: Icon(Icons.person),
                            title: Text('Profile'),
                        ),
                    ],
                ),
            ),
        );
    }
}

What this program teaches

Part

Meaning

endDrawer:

Drawer that opens from right side

Drawer()

The side menu widget

actions:

Right side buttons in the AppBar

Scaffold.of(context).openEndDrawer()

Opens the right drawer

When you run the app:

βœ… You see a menu icon on the top-right

βœ… Tap it β†’ drawer slides from the right side

βœ… Contains β€œSettings” and β€œProfile”

Difference Between drawer and endDrawer

drawer

endDrawer

Opens from LEFT

Opens from RIGHT

Common for main menu

Used for secondary menu

Uses menu icon automatically

Needs manual open button

Dependency Reminder

In pubspec.yaml:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Then run:

flutter pub get

βœ…9.bottomNavigationBar:#

Here is a very simple Flutter program that demonstrates the bottomNavigationBar: parameter in Scaffold, using MaterialApp.router() as you requested.

The bottomNavigationBar creates a navigation bar at the bottom of the screen to switch between pages.

βœ… Simple Program: bottomNavigationBar with MaterialApp.router()

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

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

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

    // βœ… Router configuration
    static final GoRouter _router = GoRouter(
        initialLocation: '/',
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
            GoRoute(
                path: '/search',
                builder: (context, state) => const SearchPage(),
            ),
            GoRoute(
                path: '/profile',
                builder: (context, state) => const ProfilePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

// ---------------- HOME PAGE ----------------
class HomePage extends StatelessWidget {
    const HomePage({super.key});

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(title: const Text('Home')),

            body: const Center(
                child: Text(
                    'Home Screen',
                    style: TextStyle(fontSize: 22),
                ),
            ),

            // βœ… bottomNavigationBar
            bottomNavigationBar: BottomNavigationBar(
                currentIndex: 0,
                onTap: (index) {
                if (index == 0) context.go('/');
                if (index == 1) context.go('/search');
                if (index == 2) context.go('/profile');
                },

                items: const [
                    BottomNavigationBarItem(
                        icon: Icon(Icons.home),
                        label: 'Home',
                    ),
                    BottomNavigationBarItem(
                        icon: Icon(Icons.search),
                        label: 'Search',
                    ),
                    BottomNavigationBarItem(
                        icon: Icon(Icons.person),
                        label: 'Profile',
                    ),
                ],
            ),
        );
    }
}

// ---------------- SEARCH PAGE ----------------
class SearchPage extends StatelessWidget {
    const SearchPage({super.key});

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(title: const Text('Search')),
            body: const Center(
                child: Text(
                    'Search Screen',
                    style: TextStyle(fontSize: 22),
                ),
            ),

            bottomNavigationBar: BottomNavigationBar(
                currentIndex: 1,
                onTap: (index) {
                    if (index == 0) context.go('/');
                    if (index == 1) context.go('/search');
                    if (index == 2) context.go('/profile');
                },
                items: const [
                    BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
                    BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
                    BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
                ],
            ),
        );
    }
}

// ---------------- PROFILE PAGE ----------------
class ProfilePage extends StatelessWidget {
    const ProfilePage({super.key});

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(title: const Text('Profile')),
            body: const Center(
                child: Text(
                    'Profile Screen',
                    style: TextStyle(fontSize: 22),
                ),
            ),

            bottomNavigationBar: BottomNavigationBar(
                currentIndex: 2,
                onTap: (index) {
                if (index == 0) context.go('/');
                if (index == 1) context.go('/search');
                if (index == 2) context.go('/profile');
                },
                items: const [
                    BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
                    BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
                    BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
                ],
            ),
        );
    }
}

What this program teaches

Part

Meaning

bottomNavigationBar:

Shows a bar at the bottom

BottomNavigationBar

The widget that contains tabs

BottomNavigationBarItem

Each button (icon + label)

context.go()

Switches page using router

currentIndex

Highlights selected tab

When you run it, you will see:

βœ… Navigation bar at bottom

βœ… Three tabs: Home, Search, Profile

βœ… Tapping a tab changes the page

πŸ“Œ Dependency Reminder

In your pubspec.yaml:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Then run:

flutter pub get

βœ…10.bottomSheet:#

Here is a very simple Flutter program that demonstrates the bottomSheet: parameter in Scaffold, using MaterialApp.router() as you requested.

The bottomSheet is a panel attached to the bottom of the screen that is always visible (unlike showModalBottomSheet, which appears and disappears).

βœ… Simple Program: bottomSheet with MaterialApp.router()

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

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

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

    // Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text('Bottom Sheet Example'),
            ),

            body: const Center(
                child: Text(
                    'Look at the bottom of the screen ↓',
                    style: TextStyle(fontSize: 20),
                ),
            ),

            // βœ… bottomSheet parameter
            bottomSheet: Container(
                height: 80,
                width: double.infinity,
                color: Colors.blueGrey,
                alignment: Alignment.center,
                child: const Text(
                    'I am a Persistent Bottom Sheet',
                    style: TextStyle(fontSize: 18, color: Colors.white),
                ),
            ),
        );
    }
}

What this program teaches

Part

Meaning

bottomSheet:

Adds a fixed sheet at the bottom

Container

Used as the sheet UI

height:

Controls how tall the sheet is

width: double.infinity

Makes it full width

Always visible

Stays on screen forever

When you run this app:

βœ… You see a bar-like panel at the bottom

βœ… It stays visible all the time

βœ… The main content is above it

This is the bottomSheet: parameter of Scaffold in action.

πŸ” Change the height & color

Try this:

bottomSheet: Container(
    height: 150,
    color: Colors.orange,
    child: const Center(
        child: Text('Bigger Bottom Sheet'),
    ),
),

Now the bottom sheet is bigger and orange.

❗ Important Difference

bottomSheet:

showModalBottomSheet()

Always visible

Opens when needed

Fixed

Temporary

Part of Scaffold

Appears over UI

Can’t drag to close

Can be dismissed

Dependency Reminder

In pubspec.yaml:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Then run:

flutter pub get

βœ…11.backgroundColor:#

Here is a very simple Flutter program that demonstrates the backgroundColor: parameter in Scaffold, using MaterialApp.router() as you requested.

The backgroundColor changes the full screen background color of the Scaffold.

βœ… Simple Program: backgroundColor with MaterialApp.router()

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

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

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

    // Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

// ---------------- HOME PAGE ----------------
class HomePage extends StatelessWidget {
    const HomePage({super.key});

    @override
    Widget build(BuildContext context) {
        return Scaffold(

            // βœ… This is the important line
            backgroundColor: Colors.lightBlue.shade100,

            appBar: AppBar(
                title: const Text('Background Color Example'),
            ),

            body: const Center(
                child: Text(
                'The Scaffold background is LIGHT BLUE',
                style: TextStyle(fontSize: 18),
                ),
            ),
        );
    }
}

What this program teaches

Part

Meaning

backgroundColor:

Sets the Scaffold’s screen color

Colors.lightBlue.shade100

Light blue background

body:

Content is placed on top of the background

When you run this app, you will see:

βœ… A light blue background

βœ… AppBar at the top

βœ… Text in the center

This color is controlled ONLY by:

backgroundColor: Colors.lightBlue.shade100,

πŸ” Try different colors

Change this line to test different colors:

backgroundColor: Colors.green,
backgroundColor: Colors.black,
backgroundColor: Colors.orangeAccent,

You’ll see the screen change immediately.

Dependency Reminder

In your pubspec.yaml:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Then run:

flutter pub get

βœ…12.resizeToAvoidBottomInset:#

Here is a very simple Flutter program that demonstrates the resizeToAvoidBottomInset: parameter in Scaffold, using MaterialApp.router() just like you asked.

This parameter controls whether the screen resizes when the keyboard opens.

βœ… Simple Program: resizeToAvoidBottomInset with MaterialApp.router()

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

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

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

    // Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(

            // βœ… IMPORTANT PARAMETER
            resizeToAvoidBottomInset: false,

            appBar: AppBar(
                title: const Text('Keyboard Resize Example'),
            ),

            body: Padding(
                padding: const EdgeInsets.all(20),
                child: Column(
                    children: const [

                        Text(
                            'Tap the text field to open the keyboard',
                            style: TextStyle(fontSize: 18),
                        ),

                        SizedBox(height: 20),

                        TextField(
                            decoration: InputDecoration(
                                border: OutlineInputBorder(),
                                labelText: 'Enter something...',
                            ),
                        ),

                        SizedBox(height: 300),

                        Text(
                            'I stay in the same place',
                            style: TextStyle(fontSize: 18),
                        ),
                    ],
                ),
            ),
        );
    }
}

What this program teaches

The key line is:

resizeToAvoidBottomInset: false,

This means:

Value

What happens when keyboard opens

true (default)

Screen moves up to avoid the keyboard βœ…

false

Screen does NOT move ❌

In this example:

βœ… Keyboard opens

βœ… Screen DOES NOT resize

βœ… Content may be hidden by keyboard

πŸ” Try changing it to true

Change this:

resizeToAvoidBottomInset: true,

Now when the keyboard opens:

βœ… The screen moves up

βœ… The text field stays visible

This is the default behavior in most forms.

When to use false?

You use:

resizeToAvoidBottomInset: false,

When:

βœ… You don’t want layout shifting

βœ… You are using your own scroll system

βœ… Full-screen UI or games

βœ… Fixed layout screens

Dependency Reminder

In your pubspec.yaml:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Then run:

flutter pub get

βœ…13.primary:#

Here is a very simple Flutter program that demonstrates the primary: parameter in Scaffold, using MaterialApp.router() (just like you asked).

The primary parameter tells Flutter whether this Scaffold should align itself to the top system area (status bar / notch) or not.

βœ… Simple Program: primary with MaterialApp.router()

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

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

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

    // Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(

            // βœ… IMPORTANT PARAMETER
            primary: false,

            appBar: AppBar(
                title: const Text('Primary Parameter Example'),
            ),

            body: const Center(
                child: Text(
                    'Set primary: false in Scaffold',
                    style: TextStyle(fontSize: 18),
                ),
            ),
        );
    }
}

What this program teaches

The key line is:

primary: false,

Value

Behavior

true (default)

Respects top safe area (status bar). βœ…

false

Does not reserve top padding. ❌

When primary: false:

βœ… The Scaffold does not automatically insert padding at the top

βœ… Content can go behind the status bar / notch

βœ… Useful for full-screen designs

On some devices, this is very noticeable near the top.

πŸ” Try changing it to true

Change to:

primary: true,

Now:

βœ… The screen respects the status bar

βœ… Automatically adds safe padding

This is the normal default behavior.

πŸ”‘ Why is this useful?

You usually set:

primary: false

When:

βœ… You want full control of padding

βœ… You use SafeArea manually

βœ… You design full-screen elements (games, videos, splash)

πŸ“Œ Dependency Reminder

In your pubspec.yaml:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Then run:

flutter pub get

βœ…14.drawerScrimColor:#

Here is a very simple Flutter program that demonstrates the drawerScrimColor: parameter in Scaffold, using MaterialApp.router() as you requested.

The drawerScrimColor changes the transparent dark overlay color that appears on the screen when the drawer is opened.

βœ… Simple Program: drawerScrimColor with MaterialApp.router()

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

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

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

    // Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(

            // βœ… IMPORTANT PARAMETER
            drawerScrimColor: Colors.red.withOpacity(0.5),

            appBar: AppBar(
                title: const Text('Drawer Scrim Color'),
            ),

            // βœ… Normal Drawer (LEFT SIDE)
            drawer: Drawer(
                child: ListView(
                    padding: EdgeInsets.zero,
                    children: const [

                        DrawerHeader(
                            decoration: BoxDecoration(color: Colors.blue),
                            child: Text(
                                'Menu',
                                style: TextStyle(color: Colors.white, fontSize: 24),
                            ),
                        ),

                        ListTile(
                            leading: Icon(Icons.home),
                            title: Text('Home'),
                        ),

                        ListTile(
                            leading: Icon(Icons.settings),
                            title: Text('Settings'),
                        ),
                    ],
                ),
            ),

            body: const Center(
                child: Text(
                    'Open the drawer to see the RED overlay',
                    style: TextStyle(fontSize: 18),
                ),
            ),
        );
    }
}

What this program teaches

The important line is:

drawerScrimColor: Colors.red.withOpacity(0.5),

This means:

βœ… When drawer opens

βœ… The background gets a red transparent overlay

βœ… Instead of the default black/gray color

Try opening the drawer and you will see:

πŸ”΄ Red shaded screen behind the drawer

πŸ” Try different colors

Change this line:

drawerScrimColor: Colors.green.withOpacity(0.4),
drawerScrimColor: Colors.blue.withOpacity(0.6),
drawerScrimColor: Colors.transparent,

If you use:

drawerScrimColor: Colors.transparent,

Then no dimming / overlay happens at all.

Why use drawerScrimColor?

It is useful when:

βœ… You want custom UI design

βœ… You want brand color behind drawer

βœ… You want no overlay at all

βœ… You want light or dark mode matching

Dependency Reminder

In your pubspec.yaml add:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Then run:

flutter pub get

βœ…15.extendBody:#

Here is a very simple Flutter program that demonstrates the extendBody: parameter in Scaffold, using MaterialApp.router() as you requested.

The extendBody parameter tells Flutter whether the body should extend behind the bottom widgets, such as the bottomNavigationBar.

βœ… Simple Program: extendBody with MaterialApp.router()

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

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

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

    // Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
            GoRoute(
                path: '/',
                builder: (context, state) => const HomePage(),
            ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(

            // βœ… IMPORTANT PARAMETER
            extendBody: true,

            appBar: AppBar(
                title: const Text('extendBody Example'),
            ),

            body: Container(
                color: Colors.orange,
                child: const Center(
                    child: Text(
                        'The orange body extends behind bottom bar',
                        style: TextStyle(fontSize: 18, color: Colors.white),
                        textAlign: TextAlign.center,
                    ),
                ),
            ),

            // βœ… Bottom Navigation Bar
            bottomNavigationBar: BottomAppBar(
                color: Colors.black,
                child: Container(
                    height: 60,
                    alignment: Alignment.center,
                    child: const Text(
                        'Bottom Bar',
                        style: TextStyle(color: Colors.white, fontSize: 18),
                    ),
                ),
            ),
        );
    }
}

What this program teaches

The key line is:

extendBody: true,

Value

Result

false (default)

Body stops above bottom bar

true βœ…

Body goes behind bottom bar

When extendBody: true:

βœ… The orange body continues under the black bar

βœ… You can see the color through the transparent parts

βœ… Useful for modern, layered UI design

πŸ” Compare with false

Change:

extendBody: false,

Now:

βœ… The orange area stops before the bar

βœ… The bar sits on top of a blank area

βœ… Classic layout style

This helps you understand the difference clearly.

When to use extendBody

Use it when:

βœ… You use BottomAppBar + FAB

βœ… You want transparent bottom bars

βœ… You design glass / blur UI

βœ… You need layered visual effects

Dependency Reminder

In your pubspec.yaml:

dependencies:
    flutter:
        sdk: flutter
    go_router: ^14.0.0

Then run:

flutter pub get

βœ…16.extendBodyBehindAppBar:#

Here is a very simple Flutter program that demonstrates the extendBodyBehindAppBar: parameter in Scaffold, using MaterialApp.router() as you requested.

This parameter allows the body to extend behind (under) the AppBar.

βœ… Simple Program: extendBodyBehindAppBar with MaterialApp.router()

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

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

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

    // βœ… Router configuration
    static final GoRouter _router = GoRouter(
        routes: [
        GoRoute(
            path: '/',
            builder: (context, state) => const HomePage(),
        ),
        ],
    );

    @override
    Widget build(BuildContext context) {
        return MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: _router,
        );
    }
}

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

    @override
    Widget build(BuildContext context) {
        return Scaffold(

            // βœ… IMPORTANT PARAMETER
            extendBodyBehindAppBar: true,

            appBar: AppBar(
                title: const Text('Behind AppBar'),
                backgroundColor: Colors.black.withOpacity(0.5), // Transparent look
            ),

            body: Container(
                decoration: const BoxDecoration(
                    gradient: LinearGradient(
                        colors: [Colors.purple, Colors.orange],
                        begin: Alignment.topCenter,
                        end: Alignment.bottomCenter,
                    ),
                ),
                child: const Center(
                    child: Text(
                        'Body is behind the AppBar',
                        style: TextStyle(fontSize: 22, color: Colors.white),
                    ),
                ),
            ),
        );
    }
}

What this program teaches

The key line is:

extendBodyBehindAppBar: true,

Value

Result

false (default)

Body starts below AppBar

true βœ…

Body goes behind AppBar

In this example:

βœ… The gradient body goes behind the AppBar

βœ… The AppBar is semi-transparent

βœ… You can see colors under the AppBar

This is commonly used for:
  • Image header effects

  • Transparent AppBar designs

  • Modern UI / full-screen UI

  • Parallax effects

πŸ” Compare with false

Try changing:

  dependencies:
      flutter:
          sdk: flutter
      go_router: ^14.0.0

Then run:

.. code-block:: bash

  flutter pub get