MaterialApp#
MaterialApp is a core widget that serves as the entry point for most Flutter apps that follow Material Design guidelines (Googleβs design system).
All Named Parameters#
Named parameters in the latest Flutter MaterialApp as of now.
MaterialApp(
home: This is the widget for the default route of the app.
title: A string that describes the app, used by the device to show what your app is called.
theme: This parameter takes a ThemeData object to define the appβs theme.
routes: A map of route names to the builder functions for those routes.
initialRoute: The route that the app shows when it starts up.
debugShowCheckedModeBanner: A boolean that determines if the debug banner is shown.
locale: Sets the appβs locale.
localizationsDelegates: A list of delegates for localization.
navigatorKey: A key that provides control over the navigator.
onGenerateRoute: A function thatβs called to generate routes that arenβt defined in the routes table.
onUnknownRoute: A function called when a named route is requested but not found.
navigatorObservers: A list of observers for the navigator.
builder: A function that wraps the whole app.
themeMode: Allows you to switch between light and dark themes.
darkTheme: Defines the theme to use when the device is in dark mode.
color: The color to use for the appβs back button in Androidβs task switcher.
highContrastTheme: A theme used when the device requests a high contrast theme.
highContrastDarkTheme: The dark version of the high contrast theme.
localeResolutionCallback: A callback thatβs used to determine the appβs locale.
supportedLocales: A list of locales that the app supports.
scrollBehavior: This allows you to customize the scroll physics and how the app responds to scrolling behavior.
checkerboardRasterCacheImages: This is a debugging parameter to show a checkerboard pattern when images are being raster cached.
checkerboardOffscreenLayers: Used for debugging to show a checkerboard on offscreen layers.
useInheritedMediaQuery: This allows the app to inherit the media query from the parent, which can help in some advanced layout scenarios.
restorationScopeId: This is used for state restoration, helping to restore the app state when the app is restarted.
onGenerateTitle: This is a function that returns the appβs title at runtime, which can be useful if you want to generate the title dynamically based on some logic.
actions: This is a map of intent keys to action objects, which can help with handling shortcuts and other actions.
onGenerateInitialRoutes: This is a function that can be used to generate the initial set of routes.
shortcuts: This allows you to define keyboard shortcuts for your app by mapping keys to intents.
scaffoldMessengerKey: β A key to use when building the ScaffoldMessenger.
showPerformanceOverlay:
key: β A Flutter Widget key for the MaterialApp.
onNavigationNotification: β A callback (NotificationListenerCallback<NavigationNotification>) for navigation notifications.
debugShowMaterialGrid: β A boolean to display a baseline grid overlay (for design/debug).
showSemanticsDebugger: β A boolean that shows an overlay of semantic (accessibility) information.
localeListResolutionCallback: β A callback (LocaleListResolutionCallback?) to choose locale when a list of locales is provided.
themeAnimationDuration: β A Duration controlling how long theme change animations take.
themeAnimationCurve: β A Curve controlling the animation curve when the theme changes.
themeAnimationStyle: β (Optional) style object for theme animation overrides.
);
Examples#
β 1. home:#
β‘οΈ The default screen (widget) shown when the app starts. Usually wrapped in a Scaffold to provide structure (app bar, body, etc.).
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
// π THIS IS THE home: PARAMETER
home: Scaffold(
body: Center(
child: Text(
'This is the HOME screen!',
style: TextStyle(fontSize: 24),
),
),
),
);
}
β 2. title:#
β‘οΈ Used by the OS (like Androidβs app switcher or iOS VoiceOver) to describe your app. Not shown in the UI.
β title: is the name of your app.
It is mainly used by:
Android task manager
Android recent apps list
Some OS-level UI elements
Accessibility tools (screen readers)
- Example:
When you open Android βRecent Appsβ β you will see this name under the app.
π Important Notes About title:
βͺ iOS does NOT use this title
βͺ iOS uses the app name from Xcode project, not this parameter.
βͺ Doesnβt display on screen
title: does NOT show inside the UI. It is not visible to the user on the home screen.
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
// π THIS IS THE title: PARAMETER
title: 'Kaftarya App',
home: Scaffold(
body: Center(
child: Text(
'MaterialApp title example',
style: TextStyle(fontSize: 22),
),
),
),
);
}
β 3. theme:#
β‘οΈ Defines the overall light theme of your appβcolors, font, icon themes, etc.
The theme: parameter controls the entire look & design of your app.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
// π THIS IS THE theme: PARAMETER
theme: ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.light,
),
home: const Scaffold(
appBar: AppBar(
title: Text('Theme Example'),
),
body: Center(
child: Text(
'This text follows the app theme!',
style: TextStyle(fontSize: 20),
),
),
),
);
}
β 4. routes:#
β‘οΈ A map of named routes and their widgets. Allows you to navigate using Navigator.pushNamed(context, β/aboutβ).
When someone opens route β/β β show HomePage
When someone opens route β/secondβ β show SecondPage
π― How navigation works
- β€ To go to another screen:
Navigator.pushNamed(context, β/secondβ);
- β€ To go back:
Navigator.pop(context);
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
// π THIS IS THE routes: PARAMETER
routes: {
'/': (context) => const HomePage(), // default home route
'/second': (context) => const SecondPage(), // second route
},
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home Page')),
body: Center(
child: ElevatedButton(
onPressed: () {
// π navigate using route name
Navigator.pushNamed(context, '/second');
},
child: const Text('Go to Second Page'),
),
),
);
}
}
class SecondPage extends StatelessWidget {
const SecondPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Second Page')),
body: Center(
child: ElevatedButton(
onPressed: () {
// π go back
Navigator.pop(context);
},
child: const Text('Go Back'),
),
),
);
}
}
β 5. initialRoute:#
β‘οΈ By default, Flutter starts at route β/β.
But if you set:
initialRoute: '/login',
Then the app opens LoginPage first, even though we have HomePage at β/β.
π― When should you use initialRoute:?
- You use it for:
showing login screen first
showing onboarding or welcome page first
opening a specific page depending on a condition
redirecting user based on saved login state
Example:
initialRoute: userLoggedIn ? '/dashboard' : '/login';
- Important Notes
The route used in initialRoute must exist inside routes:.
2. If you use home: and initialRoute: together: initialRoute wins, and home is ignored.
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,
// π THIS IS THE initialRoute PARAMETER
initialRoute: '/login',
// π These routes must contain the initialRoute
routes: {
'/': (context) => const HomePage(),
'/login': (context) => const LoginPage(),
'/dashboard': (context) => const DashboardPage(),
},
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home Page')),
body: Center(
child: ElevatedButton(
onPressed: () => Navigator.pushNamed(context, '/login'),
child: const Text('Go to Login'),
),
),
);
}
}
class LoginPage extends StatelessWidget {
const LoginPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Login Page')),
body: Center(
child: ElevatedButton(
onPressed: () => Navigator.pushNamed(context, '/dashboard'),
child: const Text('Login β Dashboard'),
),
),
);
}
}
class DashboardPage extends StatelessWidget {
const DashboardPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Dashboard')),
body: Center(
child: ElevatedButton(
onPressed: () => Navigator.pushNamed(context, '/'),
child: const Text('Go to Home'),
),
),
);
}
}
β 7. locale:#
- β‘οΈ Forces the app to use a specific language (e.g., English - United States).
locale: tells Flutter which language and region your app should use.
π― Why do we need localizationsDelegates and supportedLocales?
- Flutter needs to know:
Which languages your app supports β supportedLocales
Which translation mechanisms to use β localizationsDelegates
Without these, localization will not work.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
// π THIS IS THE locale: PARAMETER
locale: const Locale('en', 'US'), // language = English, country = United States
// π Required for localization support
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en', 'US'),
Locale('es', 'ES'),
Locale('fa', 'AF'), // Pashto / Afghanistan example
],
home: const HomePage(),
);
}
β 8. localizationsDelegates:#
β‘οΈ Provides resources (translations, formats) for specific languages, used for internationalization.
MaterialApp(
// π Required for localization support
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
);
β 10. onGenerateRoute:#
β‘οΈ Called when a route is not found in routes. You can return a custom screen dynamically.
onGenerateRoute is used when:
You want full control of navigation
You want to pass data/arguments
You want to handle dynamic routes
The route is not listed in routes: map
- This example has two pages:
HomePage
SecondPage (receives a message)
What is onGenerateRoute:?
onGenerateRoute is a function that gets called every time navigation happens.
- It gives you:
the route name (settings.name)
any arguments passed (settings.arguments)
Using this, you return:
MaterialPageRoute(builder: ...)
Why use onGenerateRoute:?
β When you want dynamic routing
β When you want to pass data easily
β When you want central navigation logic
β When you need logging, analytics, deep links
β When using Navigator 1.0 advanced features
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,
// π THIS IS onGenerateRoute:
onGenerateRoute: (settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(
builder: (context) => const HomePage(),
);
case '/second':
// π Read arguments sent to this route
final message = settings.arguments as String?;
return MaterialPageRoute(
builder: (context) => SecondPage(message: message),
);
}
// π If route doesn't exist
return MaterialPageRoute(
builder: (context) => const UnknownPage(),
);
},
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home Page')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(
context,
'/second',
arguments: 'Hello from HomePage!', // π Sending data
);
},
child: const Text('Go to Second Page'),
),
),
);
}
}
class SecondPage extends StatelessWidget {
final String? message;
const SecondPage({super.key, this.message});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Second Page')),
body: Center(
child: Text(
message ?? 'No message received',
style: const TextStyle(fontSize: 20),
),
),
);
}
}
class UnknownPage extends StatelessWidget {
const UnknownPage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text(
'404 - Page Not Found!',
style: TextStyle(fontSize: 22),
),
),
);
}
}
β 11. onUnknownRoute:#
What is onUnknownRoute:?
- It is a fallback route handler used when:
The user navigates to a route that is not registered
The route name doesnβt exist in routes:
The route name doesnβt exist in onGenerateRoute:
Without this parameter, Flutter would crash with:
Could not find a generator for route /wrongRoute
With onUnknownRoute, Flutter shows your custom 404 page instead.
Why use onUnknownRoute:?
β Prevents app crashes
β Shows a friendly error screen
β Good for production apps
β Useful for dynamic routing situations
β Helps with debugging wrong route names
Priority Order in Flutter Routing
- Flutter decides routes in this order:
routes: β if exists, use it
onGenerateRoute: β if matches logic, use it
onUnknownRoute: β fallback
Otherwise crash (if no fallback exists)
Minimal Version
onUnknownRoute: (_) => MaterialPageRoute(
builder: (_) => Text('Page Not Found'),
),
β Simple Example Showing onUnknownRoute: in MaterialApp
onUnknownRoute: is used when the user tries to navigate to a route that does NOT exist in the app.
Flutter will show a custom 404 page instead of crashing.
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,
routes: {
'/': (context) => const HomePage(),
// no other routes on purpose
},
// π THIS IS onUnknownRoute:
onUnknownRoute: (settings) {
return MaterialPageRoute(
builder: (context) => const UnknownPage(),
);
},
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home Page')),
body: Center(
child: ElevatedButton(
onPressed: () {
// π Try to open a route that DOES NOT exist
Navigator.pushNamed(context, '/wrongRoute');
},
child: const Text('Go to INVALID route'),
),
),
);
}
}
class UnknownPage extends StatelessWidget {
const UnknownPage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text(
'404 - Page Not Found',
style: TextStyle(fontSize: 24, color: Colors.red),
),
),
);
}
}
β 13. builder:#
β‘οΈ Useful to inject widgets like MediaQuery, Theme, Directionality, or overlays. builder: lets you wrap every screen with a widget.
It is useful for:
Adding a global padding
Adding a global theme wrapper
Adding overlay widgets
Adding custom font scaling
Debug borders
Global direction (LTR/RTL)
Adding a banner to every page
β Simple Example Showing builder: in MaterialApp
This example wraps every page inside a SafeArea using builder:.
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,
// π THIS IS THE builder: PARAMETER
builder: (context, child) {
return SafeArea(
child: child!, // π wraps the entire app inside SafeArea
);
},
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text(
'This page is inside SafeArea from builder:',
textAlign: TextAlign.center,
),
),
);
}
}
What does builder: do?
builder: gives you a function:
builder: (BuildContext context, Widget? child) {
return WrappedWidget(child: child);
}
This means:
β You can wrap all screens β You can modify UI globally β You can apply effects once instead of repeating in every page
Why use builder:?
β Add SafeArea globally
β No need for SafeArea on every page.
β Add Direction (RTL/LTR)
β Wrap with Directionality.
β Add global overlay (loading spinner, banner, etc.)
β Debug layouts
β Wrap with Container + border.
β Add a global text scaler
β Useful when controlling font size across the app.
Example 2: Add a red border around the whole app
builder: (context, child) {
return Container(
decoration: BoxDecoration(border: Border.all(color: Colors.red, width: 4)),
child: child,
);
},
Example 3: Force RTL (Right-to-left)
builder: (context, child) {
return Directionality(
textDirection: TextDirection.rtl,
child: child!,
);
},
Example 4: Add a global loading overlay
builder: (context, child) {
return Stack(
children: [
child!,
Positioned(
bottom: 20,
right: 20,
child: Text("Global Overlay"),
)
],
);
},
β‘ Extremely Simple Version
MaterialApp(
builder: (context, child) => child!,
)
β 14. themeMode:#
β‘οΈ Controls whether to use light theme, dark theme, or follow system setting.
themeMode: decides whether your app uses Light Theme, Dark Theme, or System Theme.
β Simple Example Showing themeMode: in MaterialApp
This example shows:
Light theme
Dark theme
themeMode to choose between them
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool isDark = false;
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
// π Light Theme
theme: ThemeData(
brightness: Brightness.light,
primarySwatch: Colors.blue,
),
// π Dark Theme
darkTheme: ThemeData(
brightness: Brightness.dark,
),
// π THIS IS THE themeMode: PARAMETER
themeMode: isDark ? ThemeMode.dark : ThemeMode.light,
home: HomePage(
toggleTheme: () {
setState(() {
isDark = !isDark;
});
},
),
);
}
}
class HomePage extends StatelessWidget {
final VoidCallback toggleTheme;
const HomePage({super.key, required this.toggleTheme});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('themeMode Example')),
body: Center(
child: ElevatedButton(
onPressed: toggleTheme,
child: const Text('Toggle Light/Dark Theme'),
),
),
);
}
}
What is themeMode:?
themeMode: tells Flutter which theme to use:
β ThemeMode.light
β Always use the light theme
β ThemeMode.dark
β Always use the dark theme
β ThemeMode.system
β Follow the device setting (userβs Android/iOS dark mode)
Minimal Example
If you donβt need a toggle button:
MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.system,
);
Example: Force Dark Mode
themeMode: ThemeMode.dark,
Example: Force Light Mode
themeMode: ThemeMode.light,
Example: Follow System Setting
themeMode: ThemeMode.system,
- β‘ Important Notes
You must provide both:
theme:
darkTheme:
- Otherwise, Flutter cannot switch between them.
themeMode: only chooses which one to use.
β 15. darkTheme:#
β‘οΈ Defines the theme used when the system is in dark mode and themeMode is set to ThemeMode.system.
What is darkTheme:?
darkTheme: defines how your app looks when dark mode is ON.
It is used only when:
themeMode: ThemeMode.dark
or the device is in dark mode with:
themeMode: ThemeMode.system
Why do we need darkTheme:?
- Because:
Dark mode needs different colors
Text contrast must change
Background becomes dark
Buttons/icons adapt to dark mode
Example: Force Dark Mode
Ignore system setting and always use dark theme:
MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.dark,
);
Example: Force Light Mode
themeMode: ThemeMode.light,
β‘ Minimal Version
MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
home: HomePage(),
);
β Simple Example Showing darkTheme: in MaterialApp
This example provides light theme + dark theme, and uses system setting to decide which one to show.
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,
// π Light Theme
theme: ThemeData(
brightness: Brightness.light,
primarySwatch: Colors.blue,
),
// π THIS IS THE darkTheme: PARAMETER
darkTheme: ThemeData(
brightness: Brightness.dark,
primarySwatch: Colors.deepPurple,
),
// π Follow system (Light / Dark)
themeMode: ThemeMode.system,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("darkTheme Example")),
body: Center(
child: Text(
'Switch your device to Dark Mode!',
style: Theme.of(context).textTheme.headlineSmall,
),
),
);
}
}
β 16. color:#
β‘οΈ Used on Android for the app preview in the task switcher (background color).
What does color: do in MaterialApp?
The color: parameter sets the primary color used by:
Android task switcher background
Window background color (sometimes)
When app is minimized or shown in βRecent Appsβ screen
The color of the βappβ square preview
It does NOT change the on-screen UI color.
Example:
color: Colors.red,
This makes your app preview in the Android recent apps menu red.
β Important
color: is NOT for UI colors.
Itβs NOT the same as:
theme.primaryColor
AppBar(color: β¦)
Scaffold(backgroundColor: β¦)
It only affects system UI / task manager.
Quick Example: Change βRecent Appsβ color
color: Colors.green,
When you open the Android Recent Apps, your app tile becomes green.
β‘ Minimal Usage
MaterialApp(color: Colors.orange)
β Simple Example Showing color: in MaterialApp
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,
// π THIS IS THE color: PARAMETER
color: Colors.blue,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text(
'MaterialApp color: example',
style: TextStyle(fontSize: 22),
),
),
);
}
}
β 17. highContrastTheme:#
What is highContrastTheme:?
It is a special theme that Flutter uses when the system requests high-contrast UI for accessibility.
- Typical changes include:
Thicker borders
Stronger color contrast
Bolder text
More visible elements
Better readability
How to view the high contrast theme?
To test it:
On Android:
Settings β Accessibility β High Contrast Text β ON
On iPhone/iPad:
Settings β Accessibility β Increase Contrast
Then reopen the app β Flutter will automatically switch to highContrastTheme.
Minimal Version
MaterialApp(
theme: ThemeData.light(),
highContrastTheme: ThemeData.highContrastLight(),
);
Example with High Contrast Dark Theme Too
highContrastTheme: ThemeData.highContrastLight(),
highContrastDarkTheme: ThemeData.highContrastDark(),
β Simple Example Showing highContrastTheme: in MaterialApp
highContrastTheme: is used when the user enables High Contrast mode on their device (for accessibility). This is often used by people with low vision.
Flutter automatically switches to this theme when High Contrast is ON in device accessibility settings.
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,
// Normal theme
theme: ThemeData(
brightness: Brightness.light,
),
// π THIS IS THE highContrastTheme: PARAMETER
highContrastTheme: ThemeData(
brightness: Brightness.light,
colorScheme: const ColorScheme.highContrastLight(),
textTheme: const TextTheme(
bodyLarge: TextStyle(fontSize: 26, fontWeight: FontWeight.bold),
bodyMedium: TextStyle(fontSize: 20),
),
),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('High Contrast Theme Example')),
body: const Center(
child: Text(
'Turn ON high contrast in device settings!',
textAlign: TextAlign.center,
),
),
);
}
}
β 18. highContrastDarkTheme:#
What is highContrastDarkTheme:?
It is the dark version of the high-contrast theme.
Used when:
Dark Mode |
High Contrast |
Which Theme? |
|---|---|---|
β No |
β No |
theme (light) |
β Yes |
β No |
darkTheme |
β Yes |
β Yes |
highContrastDarkTheme |
β No |
β Yes |
highContrastTheme |
Why do we need it?
- High-contrast dark theme improves accessibility:
Brighter text on darker backgrounds
Stronger contrast for readability
Clear separation between UI elements
Better for people with low vision
Minimal Version
MaterialApp(
darkTheme: ThemeData.dark(),
highContrastDarkTheme: ThemeData.highContrastDark(),
themeMode: ThemeMode.dark,
);
β‘ Bonus: If you also want highContrastTheme (light)
highContrastTheme: ThemeData.highContrastLight(),
highContrastDarkTheme: ThemeData.highContrastDark(),
β Simple Example Showing highContrastDarkTheme: in MaterialApp
This example gives your app:
a normal light theme
a normal dark theme
a high-contrast dark theme (for accessibility)
Flutter will automatically use highContrastDarkTheme when:
π The device is in Dark Mode AND π High Contrast is turned ON in device accessibility settings.
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,
// Normal Light Theme
theme: ThemeData(
brightness: Brightness.light,
),
// Normal Dark Theme
darkTheme: ThemeData(
brightness: Brightness.dark,
),
// π THIS IS THE highContrastDarkTheme: PARAMETER
highContrastDarkTheme: ThemeData(
brightness: Brightness.dark,
colorScheme: const ColorScheme.highContrastDark(),
textTheme: const TextTheme(
bodyLarge: TextStyle(fontSize: 26, fontWeight: FontWeight.bold),
bodyMedium: TextStyle(fontSize: 20),
),
),
// Follow system (Light / Dark)
themeMode: ThemeMode.system,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text(
'Switch your device to:\nDark Mode + High Contrast ON',
textAlign: TextAlign.center,
),
),
);
}
}
β 19. localeResolutionCallback:#
β‘οΈ You can decide how to choose the right Locale based on device settings and supported locales.
What does localeResolutionCallback: do?
- Whenever your app starts, Flutter checks:
What is the device language?
Do we support that language?
If not, which language should we choose instead?
You decide the logic.
- Example: Device = Farsi (fa_AF)
Your app supports: en_US, es_ES, ps_AF
Device is using: fa_AF (Farsi)
Since Farsi is not supported β the callback decides:
Use the fallback locale (usually en_US)
Real use cases of localeResolutionCallback
β Fallback language selection
Choose βEnglishβ if your app does not support userβs language.
β Custom language priority logic
Example: choose Pashto for any Afghanistan region.
if (deviceLocale.countryCode == 'AF') return Locale('ps', 'AF');
β Debug which locale Flutter picks
Useful while developing multilingual apps.
β Multi-language apps with dynamic behavior
Minimal Version
localeResolutionCallback: (deviceLocale, supportedLocales) {
return supportedLocales.first;
},
β‘ Example: If device language is Arabic β use English
localeResolutionCallback: (device, supported) {
if (device?.languageCode == 'ar') {
return const Locale('en', 'US');
}
return device;
},
β Simple Example Showing localeResolutionCallback: in MaterialApp
localeResolutionCallback: allows you to control which locale (language) your app should use when the userβs device language doesnβt match your supported languages.
This example prints which locale Flutter selected.
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
supportedLocales: const [
Locale('en', 'US'),
Locale('es', 'ES'),
Locale('ps', 'AF'), // Pashto
],
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
// π THIS IS localeResolutionCallback:
localeResolutionCallback: (deviceLocale, supportedLocales) {
print("π Device Locale = $deviceLocale");
// If device locale is supported β use it
if (deviceLocale != null) {
for (var locale in supportedLocales) {
if (locale.languageCode == deviceLocale.languageCode) {
print("β
Using Supported Locale = $locale");
return locale;
}
}
}
// Otherwise β fallback to first supported locale
print("β οΈ Device Not Supported β Using Default = ${supportedLocales.first}");
return supportedLocales.first;
},
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text(
'localeResolutionCallback Example',
style: TextStyle(fontSize: 22),
),
),
);
}
}
β 20. supportedLocales:#
β‘οΈ Lists all the locales your app can work with (for translation, formatting, etc.).
What does supportedLocales: do?
It defines the list of languages your app can display.
- Flutter uses this list to:
Match the device language
Decide which localization files to load
Choose fonts, direction (LTR/RTL), number formatting, etc.
Example:
supportedLocales: [
Locale('en', 'US'),
Locale('ps', 'AF'),
]
If device language = Pashto β app uses Pashto automatically.
Why you need supportedLocales?
Because Flutter cannot guess which languages your app supports. You must list them manually.
How does Flutter choose the locale?
- Flutter checks:
Device locale
If device locale is in supportedLocales β USE IT
Otherwise β use the first locale in the list
This matches βfallback localeβ concept.
Example: If phone is set to Spanish
App picks:
Locale('es', 'ES'),
If Spanish is not supported, app falls back to:
Locale('en', 'US') // first item in the list
Minimal Version
supportedLocales: [
Locale('en'),
],
β‘ Real Example for your Pashto App
supportedLocales: const [
Locale('ps', 'AF'),
Locale('en', 'US'),
],
β Simple Example Showing supportedLocales: in MaterialApp
supportedLocales: tells Flutter which languages your app supports.
- Example supports:
English (US)
Spanish (Spain)
Pashto (Afghanistan)
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
// π REQUIRED for language support
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
// π THIS IS supportedLocales:
supportedLocales: const [
Locale('en', 'US'), // English
Locale('es', 'ES'), // Spanish
Locale('ps', 'AF'), // Pashto
],
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text(
'supportedLocales Example',
style: TextStyle(fontSize: 22),
),
),
);
}
}
β 21. scrollBehavior:#
β‘οΈ Allows customizing how scrolling behaves globally (e.g., removing overscroll glow, customizing drag).
What does scrollBehavior: do?
Defines how scrolling works in the entire app:
β Removes overscroll glow
β Controls touch vs mouse drag
β Controls scroll physics
β Allows web-style scrolling
β Makes macOS/iPad scrollbars visible
β Allows middle-click scrolling on desktop
Example 2: Enable mouse + touch scrolling everywhere
scrollBehavior: const MaterialScrollBehavior().copyWith(
dragDevices: {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
},
),
- This allows scrolling with:
Touch
Mouse drag
Trackpad
Example 3: Always show scrollbars
scrollBehavior: const MaterialScrollBehavior().copyWith(
scrollbars: true,
),
Example 4: iOS Bounce Effect Everywhere
class BounceScrollBehavior extends MaterialScrollBehavior {
@override
ScrollPhysics getScrollPhysics(BuildContext context) {
return const BouncingScrollPhysics();
}
}
Then:
scrollBehavior: BounceScrollBehavior(),
β‘ Minimal Version
scrollBehavior: MaterialScrollBehavior(),
β Simple Program Showing scrollBehavior: in MaterialApp
This program removes the blue glow effect when scrolling on Android by using a custom ScrollBehavior.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
// π Custom Scroll Behavior (removes the glowing overscroll effect)
class NoGlowScrollBehavior extends ScrollBehavior {
@override
Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) {
return child; // π No glow
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
// π THIS IS scrollBehavior:
scrollBehavior: NoGlowScrollBehavior(),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("scrollBehavior Example")),
body: ListView.builder(
itemCount: 30,
itemBuilder: (context, index) {
return ListTile(
title: Text("Item ${index + 1}"),
);
},
),
);
}
}
β 22. checkerboardRasterCacheImages:#
β‘οΈ Shows a checkerboard pattern over images being rasterized (for debug performance analysis).
What does checkerboardRasterCacheImages do?
When set to true:
checkerboardRasterCacheImages: true
Flutter overlays a checkerboard grid over any raster-cached image.
- This helps developers detect:
Which images are being cached
Which UI sections are expensive
If caching is happening too often
If an animation or image is causing jank
When should you use this?
Only during debugging!
β When debugging performance
β When diagnosing slow/laggy animations
β When testing UI caching behavior
NEVER use in production β it adds ugly debug patterns.
Minimal Version
MaterialApp(
checkerboardRasterCacheImages: true,
)
β‘ Bonus Example: Disable it
checkerboardRasterCacheImages: false,
(Default is false.)
β Simple Example Showing checkerboardRasterCacheImages: in MaterialApp
This parameter is only for debugging. It shows a checkerboard pattern over images that Flutter is caching (raster cache).
- Useful when diagnosing:
jank
laggy animations
heavy UI
performance issues
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,
// π THIS IS checkerboardRasterCacheImages:
checkerboardRasterCacheImages: true,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("checkerboardRasterCacheImages Example")),
body: Center(
child: Image.network(
'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg',
width: 250,
),
),
);
}
}
β 23. checkerboardOffscreenLayers:#
β‘οΈ Shows a checkerboard over offscreen layers that are cached by Flutter (debug only).
β Simple Example Showing checkerboardOffscreenLayers: in MaterialApp
checkerboardOffscreenLayers is used only for debugging performance. It highlights (with a checkerboard pattern) any offscreen layers that Flutter is rendering.
- Offscreen layers happen when:
Widgets use Opacity
Widgets use clips (ClipRRect, ClipPath)
Widgets are rendered in a separate layer
Complex UI effects require extra drawing steps
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,
// π THIS IS checkerboardOffscreenLayers:
checkerboardOffscreenLayers: true,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("checkerboardOffscreenLayers Example")),
// π Offscreen rendering happens here because of Opacity + ClipRRect
body: Center(
child: Opacity(
opacity: 0.8,
child: ClipRRect(
borderRadius: BorderRadius.circular(30),
child: Image.network(
'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg',
width: 250,
),
),
),
),
);
}
}
What does checkerboardOffscreenLayers: do?
When set to true:
checkerboardOffscreenLayers: true
Flutter overlays a checkerboard pattern on UI parts that require offscreen rendering.
- These are expensive operations and can cause:
Jank
Poor frame rates
Slow animations
Battery usage spikes
This helps developers visually identify UI elements that are too heavy.
When offscreen layers happen?
Common reasons:
β Using Opacity()
Makes Flutter draw the widget on another layer first.
- β Using clipping widgets
ClipRRect
ClipOval
ClipPath
β Using shadows or masks
These also cause extra composition layers.
β Complex animations
Some transitions create offscreen layers temporarily.
β οΈ Important Notes
This is debug-only
Do NOT use in production
It adds ugly checkerboard patterns
Default value is: false
Minimal Version
MaterialApp(
checkerboardOffscreenLayers: true,
);
β‘ Bonus Example: Turn it OFF
checkerboardOffscreenLayers: false,
β 24. useInheritedMediaQuery:#
β‘οΈ Forces the app to use inherited MediaQuery from its parent. Useful in embedded apps or portals.
β Simple Example Showing useInheritedMediaQuery: in MaterialApp
useInheritedMediaQuery: tells Flutter whether the MediaQuery values (screen size, brightness, text scale, padding, safe area, etc.) should come from the parent widget instead of being created fresh by MaterialApp.
You mainly use it when your app is inside another Flutter app (e.g., embedding Flutter inside a native Android/iOS app).
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,
// π THIS IS useInheritedMediaQuery:
// It tells MaterialApp to use the existing MediaQuery from above.
useInheritedMediaQuery: true,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
// Getting MediaQuery info
final size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(title: const Text("useInheritedMediaQuery Example")),
body: Center(
child: Text(
"Screen Width: ${size.width}\nScreen Height: ${size.height}",
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20),
),
),
);
}
}
What does useInheritedMediaQuery: do?
β When false (default)
useInheritedMediaQuery: false
MaterialApp creates its own MediaQuery (based on screen size from platform window).
β When true
useInheritedMediaQuery: true
MaterialApp inherits MediaQuery from parent widget.
This is important when:
Embedding Flutter inside a native app view
Running Flutter inside another Flutter widget tree
You need consistent text scaling
You want to pass custom safe area insets
Why would you use this?
1. Embedding Flutter inside parent UI
If Flutter is inside a small area of a native app, the parent gives MediaQuery (size, orientation).
2. Applying custom text scaling
If parent sets:
MediaQuery(data: MediaQueryData(textScaleFactor: 1.5))
Then all Flutter children can inherit it.
3. Shared SafeArea settings
Parent SafeArea can control child widgets.
Minimal Example
MaterialApp(useInheritedMediaQuery: true)
β‘ Practical Example (Advanced)
Parent widget provides a custom MediaQuery:
return MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 2.0),
child: MaterialApp(
useInheritedMediaQuery: true,
home: HomePage(),
),
);
Now the entire app uses large text, inherited from parent.
β 25. restorationScopeId:#
β‘οΈ Allows saving and restoring UI state even after the app is killed and restarted.
β Simple Example Showing restorationScopeId: in MaterialApp
restorationScopeId enables state restoration, meaning your app can automatically remember data when closed and restore it when reopened.
This example restores the counter value even after the app is killed.
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,
// π THIS GIVES THE APP A RESTORATION SCOPE
restorationScopeId: 'app_root',
home: const CounterPage(),
);
}
}
// π A page that restores state
class CounterPage extends StatefulWidget {
const CounterPage({super.key});
@override
State<CounterPage> createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> with RestorationMixin {
// π Restorable counter value
final RestorableInt _counter = RestorableInt(0);
@override
String? get restorationId => 'counter_page';
@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
registerForRestoration(_counter, 'counter_value');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('restorationScopeId Example')),
body: Center(
child: Text(
'Counter: ${_counter.value}',
style: const TextStyle(fontSize: 24),
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
setState(() {
_counter.value++;
});
},
),
);
}
}
What is restorationScopeId:?
This ID enables State Restoration in your app.
It tells Flutter:
βThis MaterialApp is the root of all restore-able widgets.β
What does State Restoration mean?
- When the app is:
closed
killed by OS
moved to background
reopened
- Flutter restores:
counters
scroll positions
text fields
tab selections
navigation stacks
If programmed using RestorationMixin.
How it works in this example?
When user taps + button
Counter becomes 1, 2, 3β¦
If the app is killed
(or closed manually)
When reopened
Counter value is restored to the same number.
Because:
restorationScopeId: 'app_root';
And the page uses:
RestorationMixin & RestorableInt
β‘ Minimal Version
MaterialApp(
restorationScopeId: 'root',
)
When should you use state restoration?
β Apps with forms
β Multi-step processes
β Checkout screens
β Data-entry apps
β Navigation-heavy apps
β When your app must remember state after being closed
β 26. onGenerateTitle:#
β‘οΈ Instead of setting a static title, you can generate it dynamically (like reading from locale or preferences).
β Simple Example Showing onGenerateTitle: in MaterialApp
onGenerateTitle: lets you generate the app title dynamically at runtime
instead of using a fixed title: string.
- This title appears in:
Android Recent Apps list
Window title (Desktop apps)
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,
// π THIS IS onGenerateTitle:
onGenerateTitle: (context) {
// You can generate the title dynamically here
return "Welcome, Kaftarya!";
},
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text(
'onGenerateTitle Example',
style: TextStyle(fontSize: 22),
),
),
);
}
}
What does onGenerateTitle: do?
It is a callback function that returns a string.
- Flutter uses this title to display:
App name in Android Recent Apps
Window title on Flutter Desktop
App metadata in some OS environments
Why use onGenerateTitle: instead of title:?
β Create title based on system language (Localization)
onGenerateTitle: (context) => AppLocalizations.of(context)!.appName,
β Create title based on user settings
Example: βHello Johnβ, βKaftarya Adminβ, etc.
β Use data or logic to compute the title
Example: Localized Title
If you use localization (.arb):
onGenerateTitle: (context) {
return AppLocalizations.of(context)!.appTitle;
}
β‘ Minimal Version
onGenerateTitle: (_) => "My App",
Summary
Parameter |
Type |
Purpose |
|---|---|---|
title: |
String |
Fixed app title |
onGenerateTitle: |
Function |
Dynamic/app-generated title |
β 27. actions:#
β‘οΈ Maps Intents to Actions for app-wide accessibility, keyboard shortcuts, and command handling.
β Simple Program Explaining actions: in MaterialApp
actions: allows you to define global shortcut actions, often used with shortcuts: for keyboard shortcuts.
- It is mainly used on:
Desktop apps
Web apps
Apps using keyboard input
β Example: Press SPACE BAR to change background color
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
// π GLOBAL KEYBOARD SHORTCUTS
shortcuts: const {
LogicalKeySet(LogicalKeyboardKey.space): ActivateIntent(),
},
// π ACTIONS: what happens when shortcuts trigger
actions: {
ActivateIntent: CallbackAction(
onInvoke: (intent) {
print("SPACE key pressed globally!");
return null;
},
),
},
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Color color = Colors.white;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("actions: Example")),
body: Container(
color: color,
child: Center(
child: ElevatedButton(
child: const Text("Press SPACE to change color"),
onPressed: () {
setState(() {
color = Colors.primaries[
DateTime.now().millisecond % Colors.primaries.length];
});
},
),
),
),
);
}
}
What does actions: do?
It defines what happens when a shortcut is triggered.
- In the example:
shortcuts: β maps SPACE key to an ActivateIntent
actions: β what to do when that intent fires
Real uses for actions::
β Keyboard shortcuts (Ctrl+C, Ctrl+S, Enter)
β Desktop compatibility
β Accessibility actions
β Menu shortcuts
β Global hotkeys in Flutter apps
Minimal Version
actions: {
ActivateIntent: CallbackAction(onInvoke: (_) => print("activated")),
}
β 28. onGenerateInitialRoutes:#
β‘οΈ Creates the initial navigation stack when the app starts, instead of using just initialRoute.
β Simple Program for onGenerateInitialRoutes: in MaterialApp
onGenerateInitialRoutes: lets you define custom initial routes when the app starts.
This example shows how the app chooses which screen to show first depending on logic.
β Example: If userLoggedIn = true β go to Dashboard
β Otherwise β show LoginPage
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
final bool userLoggedIn = false; // change to true to test
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
// π THIS IS onGenerateInitialRoutes:
onGenerateInitialRoutes: (String initialRoute) {
if (userLoggedIn) {
return [
MaterialPageRoute(builder: (_) => const DashboardPage())
];
} else {
return [
MaterialPageRoute(builder: (_) => const LoginPage())
];
}
},
routes: {
'/login': (_) => const LoginPage(),
'/dashboard': (_) => const DashboardPage(),
},
);
}
}
class LoginPage extends StatelessWidget {
const LoginPage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(child: Text("Login Page")),
);
}
}
class DashboardPage extends StatelessWidget {
const DashboardPage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(child: Text("Dashboard Page")),
);
}
}
What does onGenerateInitialRoutes: do?
It decides which routes to load first
Runs before any navigation happens
Allows custom app-launch behavior
Useful for:
login redirection
onboarding flow
saved state restoration
deep links
β 29. shortcuts:#
β‘οΈ Maps keyboard keys (or gestures) to Intents, supporting shortcut features for desktop or web apps.
β Simple Program for shortcuts: in MaterialApp
shortcuts: maps keyboard keys to Intents.
Here pressing CTRL + N prints a message.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
// π THIS IS shortcuts:
shortcuts: const {
SingleActivator(LogicalKeyboardKey.keyN, control: true):
NewIntent(),
},
actions: {
NewIntent: CallbackAction<NewIntent>(
onInvoke: (intent) {
print("CTRL + N pressed!");
return null;
},
),
},
home: const HomePage(),
);
}
}
class NewIntent extends Intent {
const NewIntent();
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(child: Text("Press CTRL + N")),
);
}
}
- β What does shortcuts: do?
Listens to keyboard combinations.
Maps keyboard key β Intent.
β 30. scaffoldMessengerKey:#
β Simple Example Showing scaffoldMessengerKey: in MaterialApp
scaffoldMessengerKey: allows you to show SnackBars from anywhere β even without BuildContext, even outside widgets (e.g., services, controllers).
We will create:
a global ScaffoldMessenger key
a button that shows a SnackBar using the key
(NOT using ScaffoldMessenger.of(context))
β Complete Working Example
import 'package:flutter/material.dart';
// π Create a global key for ScaffoldMessenger
final GlobalKey<ScaffoldMessengerState> messengerKey =
GlobalKey<ScaffoldMessengerState>();
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
// π THIS IS scaffoldMessengerKey:
scaffoldMessengerKey: messengerKey,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("scaffoldMessengerKey Example")),
body: Center(
child: ElevatedButton(
onPressed: () {
// π Showing snackbar WITHOUT context
messengerKey.currentState!.showSnackBar(
const SnackBar(
content: Text("Hello from scaffoldMessengerKey!"),
),
);
},
child: const Text("Show SnackBar"),
),
),
);
}
}
What is scaffoldMessengerKey:?
It gives your app a global ScaffoldMessenger controller so you can show:
SnackBars
MaterialBanners
Hide existing SnackBars
from anywhere, not only from widgets.
Why use scaffoldMessengerKey?
Because this works:
messengerKey.currentState!.showSnackBar(...)
- Even inside:
ViewModels
Controllers
Services
Bloc / Provider
Background logic
Async callbacks
You donβt need:
ScaffoldMessenger.of(context)
Which requires a widget context.
Minimal Version
MaterialApp(
scaffoldMessengerKey: GlobalKey<ScaffoldMessengerState>(),
)
β‘ Real Use Cases
Showing SnackBar when a network request fails
Showing SnackBar from API service class
Showing messages from Bloc/Provider
Showing global messages such as:
Login success
Error sending request
Data saved
Payment failed
β 31. showPerformanceOverlay:#
β Simple Example Showing showPerformanceOverlay: in MaterialApp
The performance overlay is a built-in Flutter debugging tool. It shows FPS, GPU usage, UI thread performance, and frame rendering stats.
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,
// π THIS IS showPerformanceOverlay:
showPerformanceOverlay: true,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("showPerformanceOverlay Example")),
body: const Center(
child: Text(
"Performance Overlay is Visible\nLook at the top-right corner!",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 20),
),
),
);
}
}
What does showPerformanceOverlay: do?
When set to true:
showPerformanceOverlay: true
β Top graph: UI thread
Shows how fast Flutter is building frames (should stay under 16ms for 60fps).
β Bottom graph: GPU thread
Shows how fast Flutter is painting frames.
If bars go above the line β frame drops or jank.
What is it used for?
This is a debug tool, used to check:
FPS (frames per second)
UI lag
GPU overload
Slow animations
Rendering problems
Expensive widgets
jank issues
This is extremely helpful for game-like apps or complex animations.
β οΈ Important Notes
Only for debugging
Do NOT use in production
Adds performance graphs on screen
Default is: false
Minimal Version
MaterialApp(showPerformanceOverlay: true)
β 32. key:#
β Now: Simple program for key: parameter in MaterialApp
The key: parameter is used to identify this instance of MaterialApp in the widget tree.
It is useful when:
Rebuilding UI
Reloading widgets
Controlling widget identity
Testing
Simple Example Showing key: in MaterialApp
import 'package:flutter/material.dart';
void main() {
runApp(
// π THIS IS THE key: PARAMETER
MyApp(key: const Key('MyMaterialApp')),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key}); // receives the key
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text(
'key: parameter example',
style: TextStyle(fontSize: 22),
),
),
);
}
}
What does key: actually do?
key: helps Flutter:
Identify a widget uniquely
Decide when to reuse or rebuild a widget
Improve performance
Maintain state correctly
Example:
MaterialApp(
key: const ValueKey('main_app'),
)
If you donβt change the key β Flutter keeps the same app If you change the key β Flutter forces a rebuild
β Super simple explanation
key: is an ID for a widget
Like a student ID number:
Not visible
Used internally
Helps Flutter track things
β 34. debugShowMaterialGrid:#
β Simple program for debugShowMaterialGrid: in MaterialApp
This shows a material design grid on top of your app for UI alignment checking (debugging only).
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
// π THIS IS debugShowMaterialGrid:
debugShowMaterialGrid: true,
home: const Scaffold(
body: Center(
child: Text(
"Material Grid ON",
style: TextStyle(fontSize: 24),
),
),
),
));
}
- What happens?
You will see a grid overlay
It helps with:
Alignment
Spacing
Layout precision
Used only in design & debugging
Never use in production
β 35. showSemanticsDebugger:#
What is showSemanticsDebugger?
showSemanticsDebugger is used for accessibility debugging.
When set to true β Flutter shows an overlay box on every widget.
The overlay displays semantic information like:
Label
Role (button, text, image, etc.)
Value
Accessibility hints
This is mainly used to debug apps for visually-impaired users who use screen readers such as:
TalkBack (Android)
VoiceOver (iOS)
What you will SEE on screen
When you run the app with:
showSemanticsDebugger: true,
You will notice:
β Colored rectangles around widgets
β Labels on Text and Buttons
β Hierarchy of widget accessibility tree
This shows how screen readers βseeβ your app.
β When should you use this?
- Use it when:
You are building an accessible app
Testing for blind users
Improving UX for screen readers
Set it back to false (or remove it) for production:
showSemanticsDebugger: false,
β Simple program to describe showSemanticsDebugger:
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(
// β
This turns ON the Semantics Debugger overlay
showSemanticsDebugger: true,
home: Scaffold(
appBar: AppBar(
title: const Text('Semantics Demo'),
),
body: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Hello Kaftarya'),
SizedBox(height: 20),
ElevatedButton(
onPressed: null,
child: Text('Press Me'),
),
],
),
),
),
);
}
}
β 36. localeListResolutionCallback:#
What is localeListResolutionCallback?
This parameter is used to:
β Detect the userβs device language(s)
β Compare them with your appβs supported languages
β Choose the best matching language for your app
It runs automatically when the app starts and receives:
(List<Locale>? deviceLocales, Iterable<Locale> supportedLocales)
In simple words:
βFlutter hands you the phoneβs language list and your appβs language list β now YOU choose which one to use.β
Example Scenario
- Assume:
Phone language = Spanish (es_ES)
Your supported languages are: English, Spanish, French
This function will:
MATCH FOUND β Spanish is selected
If phone language = German (de_DE)β¦
NO MATCH β Default to English
β When should you use this?
You use localeListResolutionCallback when:
Supporting multiple languages
Want to customize fallback logic
Want full control over language selection
Key Difference
Feature |
Purpose |
|---|---|
locale |
Force one fixed language |
supportedLocales |
List of allowed languages |
localeResolutionCallback |
Handles only one device locale |
β localeListResolutionCallback |
Handles multiple device locales (best choice) |
β Simple program to describe localeListResolutionCallback:
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(
// π Languages your app supports
supportedLocales: const [
Locale('en', 'US'),
Locale('es', 'ES'),
Locale('fr', 'FR'),
],
// β
This is the main focus of your question
localeListResolutionCallback: (List<Locale>? deviceLocales,
Iterable<Locale> supportedLocales) {
print("Device locales: $deviceLocales");
print("Supported locales: $supportedLocales");
// Example logic: If device is Spanish β return Spanish
for (var locale in deviceLocales!) {
for (var supported in supportedLocales) {
if (locale.languageCode == supported.languageCode) {
return supported;
}
}
}
// If nothing matches β fallback to English (US)
return const Locale('en', 'US');
},
home: const Scaffold(
body: Center(
child: Text(
"Hello Kaftarya",
style: TextStyle(fontSize: 24),
),
),
),
);
}
}
β 37. themeAnimationDuration:#
What is themeAnimationDuration?
themeAnimationDuration controls:
How long the animation takes when switching between themes
themeAnimationDuration: Duration(seconds: 2)
- This means:
When the theme changes (light β dark),
The animation will take 2 seconds to complete
Try changing the duration
Try these:
themeAnimationDuration: Duration(milliseconds: 200)
π Very fast animation
themeAnimationDuration: Duration(seconds: 5)
π Very slow animation (clear smooth transition)
What you will see
When you press Change Theme:
β Background color slowly changes
β Text color transitions smoothly
β AppBar color animates
Not instant jump β itβs animated.
β When to use this
- Use it when:
You allow users to switch light / dark mode
You want a smooth professional animation effect
You want control over animation speed
β οΈ Important Note
This only works when:
themeMode is changed at runtime
If the theme is fixed, this animation wonβt apply.
β Simple program to describe themeAnimationDuration:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool isDarkMode = false;
@override
Widget build(BuildContext context) {
return MaterialApp(
// β
This controls how fast the theme change animates
themeAnimationDuration: const Duration(seconds: 2),
// Light theme
theme: ThemeData.light(),
// Dark theme
darkTheme: ThemeData.dark(),
// Switch between them
themeMode: isDarkMode ? ThemeMode.dark : ThemeMode.light,
home: Scaffold(
appBar: AppBar(
title: const Text('Theme Animation Demo'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
setState(() {
isDarkMode = !isDarkMode;
});
},
child: const Text('Change Theme'),
),
),
),
);
}
}
β 38. themeAnimationCurve:#
What is themeAnimationCurve?
themeAnimationCurve defines how the animation behaves over time.
In simple words:
It controls HOW the animation moves, not how long it takes.
Example
themeAnimationCurve: Curves.easeInOut
This means:
Starts slow β
Gets fast in the middle β
Ends slow β
Try other curves
You can change the curve to see different animations:
themeAnimationCurve: Curves.linear // constant speed
themeAnimationCurve: Curves.bounceOut // bouncy effect
themeAnimationCurve: Curves.easeIn // slow β fast
themeAnimationCurve: Curves.fastOutSlowIn // very smooth
Each one gives a different feel to the theme change.
β Quick Difference Table
Parameter |
Controls |
|---|---|
themeAnimationDuration |
How long the animation takes |
β themeAnimationCurve |
How it moves during that time |
So if you set:
Duration(seconds: 2)
Curves.bounceInOut
β The animation takes 2 seconds and bounces while changing
β When to use this
- Use it when:
You care about UX / UI quality
You want natural looking transitions
You want your app to feel premium and smooth
β Simple program to describe themeAnimationCurve:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool isDarkMode = false;
@override
Widget build(BuildContext context) {
return MaterialApp(
// β
Duration of the animation
themeAnimationDuration: const Duration(seconds: 2),
// β
Shape/style of the animation
themeAnimationCurve: Curves.easeInOut,
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: isDarkMode ? ThemeMode.dark : ThemeMode.light,
home: Scaffold(
appBar: AppBar(title: const Text('Theme Curve Demo')),
body: Center(
child: ElevatedButton(
onPressed: () {
setState(() {
isDarkMode = !isDarkMode;
});
},
child: const Text('Change Theme'),
),
),
),
);
}
}
β 39. themeAnimationStyle:#
What is themeAnimationStyle in simple words?
It controls WHAT TYPE of animation is used when the theme changes.
Value |
Meaning |
|---|---|
AnimationStyle.noAnimation |
Switch theme instantly (no movement) |
AnimationStyle.standard |
Smooth, normal theme animation β |
AnimationStyle.custom |
You define your own style |
Try this experiment
Change:
themeAnimationStyle: AnimationStyle.noAnimation,
Now when you press Change Theme:
β The screen changes instantly β No fade / smooth effect
Then switch to:
themeAnimationStyle: AnimationStyle.standard,
β Relationship with others
Parameter |
Controls |
|---|---|
themeAnimationDuration |
How long it takes |
themeAnimationCurve |
How it moves |
β themeAnimationStyle |
What type of animation |
β Simple example using themeAnimationStyle
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool isDark = false;
@override
Widget build(BuildContext context) {
return MaterialApp(
// β
NEW PARAMETER: Theme Animation Style
themeAnimationStyle: AnimationStyle.standard,
// These two still work with it
themeAnimationDuration: const Duration(seconds: 2),
themeAnimationCurve: Curves.easeInOut,
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: isDark ? ThemeMode.dark : ThemeMode.light,
home: Scaffold(
appBar: AppBar(
title: const Text("Theme Animation Style"),
),
body: Center(
child: ElevatedButton(
onPressed: () {
setState(() {
isDark = !isDark;
});
},
child: const Text("Change Theme"),
),
),
),
);
}
}