MaterialApp, Scaffold and theming

Flutter · Essentials · 12 min

A consistent theme makes the app look professional and lets you support dark mode and branding in one place.

`MaterialApp` sets up the app: theme, localization, navigation and the home screen. (CupertinoApp is the iOS-styled alternative; most apps use Material and adapt where needed.)

`Scaffold` provides the standard screen structure: appBar, body, floatingActionButton, drawer, bottomNavigationBar / NavigationBar, and it hosts SnackBars via ScaffoldMessenger.of(context).showSnackBar(...).

Flutter uses Material 3 by default. Build a theme from one seed color:

theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal)),
darkTheme: ThemeData(colorScheme: ColorScheme.fromSeed(
    seedColor: Colors.teal, brightness: Brightness.dark)),
themeMode: ThemeMode.system,

Widgets read the theme through Theme.of(context): use colorScheme.primary, colorScheme.surface, and text styles like textTheme.headlineSmall instead of hard-coded colors and font sizes. Then dark mode and rebranding work automatically.

Customize components globally with component themes in ThemeData, e.g. filledButtonTheme, inputDecorationTheme, cardTheme. Override locally by wrapping a subtree in Theme(data: ..., child: ...) or passing a style.

Custom fonts are declared in pubspec.yaml and set with fontFamily or a text theme. Respect the user's text scaling: avoid fixed heights that clip enlarged text.

Example

import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
      theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal)),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal, brightness: Brightness.dark),
      ),
      home: const HomeScreen(),
    ));
class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final colors = Theme.of(context).colorScheme;
    return Scaffold(
      appBar: AppBar(title: const Text('Inbox')),
      body: Center(child: Text('No mail', style: TextStyle(color: colors.primary))),
      floatingActionButton: FloatingActionButton(
        onPressed: () => ScaffoldMessenger.of(context)
            .showSnackBar(const SnackBar(content: Text('Compose'))),
        child: const Icon(Icons.edit),
      ),
    );
  }
}

Remember

  • MaterialApp configures theme and navigation; Scaffold structures a screen
  • Derive colors with ColorScheme.fromSeed; support dark mode with darkTheme
  • Read colors and text styles from Theme.of(context)

Watch out for

  • Hard-coding colors throughout widgets, which breaks dark mode and rebranding.

Check yourself

  1. Where should a widget get its primary color so that dark mode works automatically?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.flutter.dev/cookbook/design/themes