Build and publish a Flutter-based app for the App Store and Google Play — revisited and refreshed for 2026, now that Material 3 is firmly the default design language in Flutter.
TL:DR – n this article we add Progress indicators, Selection controls (Radio buttons, checkboxes and switches), SnackBar via ScaffoldMessenger, Bottom Navigation Bar, and Text fields — all updated to reflect current Flutter 3.x and Material 3 conventions.
Contents
What's changed in 2026
The most practically important change for this article is the deprecation of Scaffold.of(context).showSnackBar() and the GlobalKey workaround that went with it. The correct approach is now ScaffoldMessenger.of(context).showSnackBar(), which has been the recommended pattern for several years. Similarly, textTheme.bodyText1 is gone — the Material 3 text theme uses names like bodyLarge, bodyMedium, and bodySmall. And BottomNavigationBarItem's title parameter was renamed to label some time ago. This refresh updates all of those.
Adding Material Components widgets to our app page
With Material 3 as the baseline, let's work through the remaining components. The goal is still to explore what's available out of the box before we start wiring things up to real functionality.
Progress indicators
Progress indicators express an unspecified wait time or display the length of a process, letting the user know the app is doing something and hasn't simply frozen.
The first kind, LinearProgressIndicator, shows progress along a line. There are two variations: determinate (a specific value at each point in time) and indeterminate (no specific value — it just animates). The second kind, CircularProgressIndicator, shows progress along a circular arc. Under Material 3 these widgets have a refreshed visual style with updated default colours drawn from your app's colour scheme.
Note that Colors.primaries[16] from the original code is a fragile approach — the primaries list has a fixed length and indexing beyond it will throw a range error. Better to use a colour from your theme directly, for example Theme.of(context).colorScheme.surfaceVariant.
ExpansionTile(
leading: Icon(Icons.refresh),
title: Text('Progress Indicators'),
subtitle: Text('LinearProgressIndicator, CircularProgressIndicator'),
children: [
Text(
'Linear',
style: Theme.of(context).textTheme.bodyLarge,
),
LinearProgressIndicator(
value: 0.8,
),
SizedBox(height: 12),
Text(
'Circular',
style: Theme.of(context).textTheme.bodyLarge,
),
CircularProgressIndicator(),
],
),

Under Material 3 these look noticeably more refined — the linear indicator in particular has a rounder, more considered appearance.
Selection controls — Radio buttons, checkboxes and switches
These are the out-of-the-box widgets for selection control. The API is largely unchanged, though the visual style under Material 3 is updated with better contrast and more expressive state indicators.
ExpansionTile(
leading: Icon(Icons.radio_button_checked),
title: Text('Selection controls'),
subtitle: Text('RadioListTile, CheckboxListTile, SwitchListTile'),
children: [
Text(
'RadioListTile',
style: Theme.of(context).textTheme.bodyLarge,
),
RadioListTile(
title: const Text('A radio button in a RadioListTile'),
value: true,
onChanged: null,
groupValue: null,
),
Text(
'CheckboxListTile',
style: Theme.of(context).textTheme.bodyLarge,
),
CheckboxListTile(
title: Text('A checkbox in a CheckboxListTile'),
value: true,
onChanged: null,
),
Text(
'SwitchListTile',
style: Theme.of(context).textTheme.bodyLarge,
),
SwitchListTile(
title: Text('A switch in a SwitchListTile'),
value: true,
onChanged: null,
),
],
),

Following the same pattern, a simple Slider can be added. One thing worth noting: these controls render identically on iOS and Android by default, which may not always be what you want. Flutter does offer platform-adaptive patterns, and the Material 3 defaults are more visually distinctive than earlier versions — but if you need truly native-feeling controls on each platform, that's a separate conversation.

SnackBar via ScaffoldMessenger
A SnackBar is a lightweight message with an optional action that briefly appears at the bottom of the screen. The original version of this article used a GlobalKey workaround to call showSnackBar — that approach is now fully deprecated and should not be used in any new code.
The current and correct API is ScaffoldMessenger.of(context).showSnackBar(). ScaffoldMessenger was introduced specifically to solve the context-related problems that made the GlobalKey hack necessary in the first place. It handles SnackBars at the navigator level, which means they survive page transitions cleanly.
ScaffoldMessenger manages SnackBars for descendant Scaffolds. It handles showing and hiding SnackBars, queuing multiple SnackBars, and removing the current SnackBar when a new one is shown.
// No GlobalKey needed — just use ScaffoldMessenger
ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Hello SnackBar'),
duration: Duration(seconds: 3),
),
);
},
child: Text('Show SnackBar'),
),

Much cleaner, and no workarounds required.
Bottom Navigation Bar
A tab bar at the bottom of the screen for switching between a small number of top-level views. BottomNavigationBar remains the standard built-in widget for this. One API change to be aware of: the title parameter on BottomNavigationBarItem was renamed to label — using the old name will produce a deprecation warning in current Flutter versions.
It's also worth knowing that Material 3 introduces a NavigationBar widget as the M3-native alternative to BottomNavigationBar. The two are functionally similar but NavigationBar follows M3 styling conventions more closely. For a new app targeting 2026, NavigationBar is the better starting point.
// Modern M3 approach: NavigationBar
bottomNavigationBar: NavigationBar(
selectedIndex: 0,
onDestinationSelected: (index) {
// handle tab change
},
destinations: const [
NavigationDestination(
icon: Icon(Icons.new_releases_outlined),
selectedIcon: Icon(Icons.new_releases),
label: 'New',
),
NavigationDestination(
icon: Icon(Icons.track_changes_outlined),
selectedIcon: Icon(Icons.track_changes),
label: 'Track',
),
NavigationDestination(
icon: Icon(Icons.person_add_outlined),
selectedIcon: Icon(Icons.person_add),
label: 'Add',
),
],
),

Even without any navigation logic wired up, this immediately gives the screen more structure and communicates the app's shape to the user.
Text fields
Flutter's text field support remains excellent, and the Material 3 redesign gives TextField a noticeably more polished appearance — cleaner borders, better focus states, and improved label animation. The core API is unchanged.
ExpansionTile(
leading: Icon(Icons.input),
title: Text('Text fields'),
subtitle: Text('TextField'),
children: [
Text(
'obscureText — for example, for passwords',
style: Theme.of(context).textTheme.bodyLarge,
),
TextField(
obscureText: true,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
),
),
],
),

A note on deprecated APIs in older Flutter tutorials
If you've been following older Flutter tutorials or working from code written before Flutter 3.16, it's worth doing a quick audit before building further. The most common issues you'll encounter are:
textTheme.bodyText1/bodyText2— replaced bybodyLarge,bodyMedium,bodySmall.Scaffold.of(context).showSnackBar()— replaced byScaffoldMessenger.of(context).showSnackBar().BottomNavigationBarItem(title:)— thetitleparameter is nowlabel.useMaterial3: truein ThemeData — no longer needed; Material 3 is the default and the flag is deprecated.
Flutter's own migration guides are thorough and worth bookmarking. Running flutter analyze on an older codebase will surface most of these quickly.
That wraps up the portion of this journey exploring the basics of the main Material Components available in Flutter. With Material 3 now the default in Flutter 3.44, the widgets covered here look better than ever out of the box. Next, we'll focus on turning this component showcase into a real, functional app and getting it published to the App Store and Google Play. You can find the full list of current Material Components in the Material 3 component documentation and the corresponding Flutter implementations in the Flutter Material widgets catalogue.