Skip to content

Platform Widget Catalog

Lance Johnstone edited this page Mar 17, 2023 · 5 revisions

Here lies within the list of platform widgets that you can easily use to simplify your Material and Cupertino styles applications...

Platform Widgets

These are the building blocks that you can use to replace your widgets with to get both Material and Cupertino styled widgets.

Platform Scaffold

A Scaffold that provides the correctly hosted header (AppBar) and navigation bar (Bottom Bar) for each platform. Uses Scaffold for material or CupertinoTabScaffold for cupertino with bottom tabs or CupertinoPageScaffold for cupertino without bottom tabs.

return PlatformScaffold(
  appBar: PlatformAppBar()
  body: _buildContent(),
  bottomNavBar: PlatformNavBar(),
  iosContentPadding: false,
  iosContentBottomPadding: false
);

Note that the use of iosContentPadding = true is only required if the content is being obstructed behind the appBar. iosContentBottomPadding is used if the content needs to be above the navBar and not go behind it. This will not have the translucent effect for iOS when these are set to true. If that is desirable, then the scrolling and content alignment need to be managed yourself.

Uses:

Platform Widget Extended props add...
Material Scaffold material: (_, __) => MaterialScaffoldData(...)
Cupertino CupertinoPageScaffold cupertino: (_, __) => CupertinoPageScaffoldData(...)
Cupertino CupertinoTabScaffold cupertino: (_, __) => CupertinoPageScaffoldData(...)

NOTE

If you need to have Scaffold with tabs it is better to use PlatformTabScaffold.

Platform Tab scaffold

Note: Using PlatformTabScaffold provides a more refined and flexible experience than using PlatformScaffold.

A Scaffold that provides the correctly hosted header (AppBar) and navigation bar (Bottom Bar) for each platform. Uses Scaffold for material or CupertinoTabScaffold for cupertino with bottom tabs.

return PlatformTabScaffold(
  tabController: tabController,
  appBarBuilder: (_, index) => PlatformAppBar(),
  bodyBuilder: (context, index) => _buildContent(index),
  items: _items(context),
);

More more detailed example look at:

Note that the use of iosContentPadding = true is only required if the content is being obstructed behind the appBar. iosContentBottomPadding is used if the content needs to be above the navBar and not go behind it. This will not have the translucent effect for iOS when these are set to true. If that is desirable, then the scrolling and content alignment need to be managed yourself.

Uses:

Platform Widget Extended props add...
Material Scaffold material: (_, __) => MaterialTabScaffoldData(...)
Material Scaffold materialTabs: (_, __) => MaterialNavBarData(...)
Cupertino CupertinoPageScaffold cupertino: (_, __) => CupertinoTabScaffoldData(...)
Cupertino CupertinoTabScaffold cupertinoTabs: (_, __) => CupertinoTabBarData(...)

Platform App bar

The AppBar is the top Header bar with a title, left-side or right-side buttons. Uses AppBar for material or CupertinoNavigationBar for cupertino.

return PlatformAppBar(
    title: new Text('Platform Widgets'),
    leading: PlatformIconButton(),
    trailingActions: <Widget>[
      PlatformIconButton(),
    ],
  );

In Cupertino if a solid color header is required and there is a ListView on the page, you would need to add some alpha to the color so that the ListView is not pushed down too far

     appBar: PlatformAppBar(
       title: Text('iOS Colored Header'),
       cupertino: (_, __) => CupertinoNavigationBarData(
             // Issue with cupertino where a bar with no transparency
             // will push the list down. Adding some alpha value fixes it (in a hacky way)
             backgroundColor: Colors.lightGreen.withAlpha(254),
           ),
     ),

Uses:

Platform Widget Extended props add...
Material AppBar material: (_, __) => MaterialAppBarData(...)
Cupertino CupertinoNavigationBar cupertino: (_, __) => CupertinoNavigationBarData(...)

Platform Nav bar

The NavBar is placed at the bottom of the page with a set of buttons that typically navigate between screens. Implementing this widget requires the parent widget to manage the currentIndex of the page and to set PlatformNavBar.currrentIndex. Uses BottomAppBar with BottomNavigationBar for material or CupertinoTabBar for cupertino.

return PlatformNavBar(
  currentIndex: _selectedTabIndex,
  itemChanged: (index) => setState(
        () {
          _selectedTabIndex = index;
        },
      ),
  items: [
    BottomNavigationBarItem(),
    BottomNavigationBarItem(),
  ],
);

Uses:

Platform Widget Extended props add...
Material BottomAppBar material: (_, __) => MaterialNavBarData(...)
Cupertino CupertinoTabBar cupertino: (_, __) => CupertinoTabBarData(...)

Platform Alert Dialog

The AlertDialog will render a caption/title, body/text and a set of action buttons specific for the platform. Uses AlertDialog for material or CupertinoAlertDialog for cupertino.

Note use showPlatformDialog instead of either showDialog from the Material library or showCupertinoDialog from the Cupertino library.

showPlatformDialog(
  context: context,
  builder: (_) => PlatformAlertDialog(
    title: Text('Alert'),
    content: Text('Some content'),
    actions: <Widget>[
      PlatformDialogAction(),
      PlatformDialogAction(),
    ],
  ),
);

Uses:

Platform Widget Extended props add...
Material AlertDialog material: (_, __) => MaterialAlertDialogData(...)
Cupertino CupertinoAlertDialog cupertino: (_, __) => CupertinoAlertDialogData(...)

Platform Alert dialog action

The DialogAction widget is used to describe the set of buttons on the AlertDialog. Uses TextButton for material or CupertinoDialogAction for cupertino.

PlatformDialogAction(
  child: PlatformText('Cancel'),
  onPressed: () => Navigator.pop(context),
),

Uses:

Platform Widget Extended props add...
Material TextButton material: (_, __) => MaterialDialogActionData(...)
Cupertino CupertinoDialogAction cupertino: (_, __) => CupertinoDialogActionData(...)

Platform List Tile

library version >=3.1.0

A platform list tile that renders a ListTile for material or a CupertinoListTile for cupertino.

PlatformListTile(
  title: 'title', 
  onTap: () => Navigator.pop(context),
),

Platform Elevated button

A platform button that renders an ElevatedButton or ElevatedButton.icon for material or a CupertinoButton.filled for cupertino.

PlatformElevatedButton(
  child: PlatformText('Cancel'),
  onPressed: () => Navigator.pop(context),
),

Note

The title is a required parameter as that is a required parameter for the CupertinoListTile. You can have different titles between material and cupertino when setting the material or cupertino properties

Uses:

Platform Widget Extended props add...
Material ListTile material: (_, __) => MaterialListTileData(...)
Cupertino CupertinoListTile cupertino: (_, __) => CupertinoListTileData(...)

Note The icon can only be applied to a the material ElevatedButton when the icon property is set. There is no corresponding icon button for cupertino. Cupertino to support backward compatibility supports rendering the CupertinoButton when the originalStyle property is set.

Uses:

Platform Widget Extended props add...
Material ElevatedButton material: (_, __) => MaterialElevatedButtonData(...)
Material ElevatedButton.icon material: (_, __) => MaterialElevatedButtonData(icon: Icon(Icons...))
Cupertino CupertinoButton.filled cupertino: (_, __) => CupertinoElevatedButtonData(...)
Cupertino CupertinoButton cupertino: (_, __) => CupertinoElevatedButtonData(originalStyle: true)

Platform Text button

A platform button that renders an TextButton or TextButton.icon for material or a CupertinoButton for cupertino.

PlatformElevatedButton(
  child: PlatformText('Cancel'),
  onPressed: () => Navigator.pop(context),
),

Note The icon can only be applied to a the material ElevatedButton when the icon property is set. There is no corresponding icon button for cupertino. Cupertino to support backward compatibility supports rendering the CupertinoButton.filled when the originalStyle property is set.

Uses:

Platform Widget Extended props add...
Material TextButton material: (_, __) => MaterialTextButtonData(...)
Material TextButton.icon material: (_, __) => MaterialTextButtonData(icon: Icon(Icons...))
Cupertino CupertinoButton cupertino: (_, __) => CupertinoTextButtonData(...)
Cupertino CupertinoButton.filled cupertino: (_, __) => CupertinoTextButtonData(originalStyle: true)

Platform Text

A widget that will render uppercase for material. Cupertino will remain unchanged.

return PlatformText('Cancel');

Platform Switch

A switch widget that will use a Switch for material or a CupertinoSwitch for cupertino.

return PlatformSwitch(
  onChanged: (bool value) {},
  value: value,
);

Uses:

Platform Widget Extended props add...
Material Switch material: (_, __) => MaterialSwitchData(...)
Cupertino CupertinoSwitch cupertino: (_, __) => CupertinoSwitchData(...)

Platform Slider

A slider widget that will use a Slider for material or a CupertinoSlider for cupertino

return PlatformSlider(
  onChanged: (bool value) {},
  value: value,
);

Uses:

Platform Widget Extended props add...
Material Slider material: (_, __) => MaterialSliderData(...)
Cupertino CupertinoSlider cupertino: (_, __) => CupertinoSliderData(...)

Platform Text field

A text field widget that will use a TextField for material or a CupertinoTextField for cupertino.

return PlatformTextField();

Uses:

Platform Widget Extended props add...
Material TextField material: (_, __) => MaterialTextFieldData(...)
Cupertino CupertinoTextField cupertino: (_, __) => CupertinoTextFieldData(...)

Platform Text form field

A text field widget that will use a TextFormField for material or a CupertinoTextFormFieldRow for cupertino.

return PlatformTextFormField();

Uses:

Platform Widget Extended props add...
Material TextFormField material: (_, __) => MaterialTextFormFieldData(...)
Cupertino CupertinoTextFormFieldRow cupertino: (_, __) => CupertinoTextFormFieldData(...)

Platform Icon button

A clickable (tappable) button with an icon. Uses IconButton for material or CupertinoButton for cupertino.

return PlatformIconButton(
  onPressed: () => print('info pressed'),
  materialIcon: Icon(Icons.info),
  cupertinoIcon: Icon(
    CupertinoIcons.info,
    size: 28.0,
  ),
);

Uses:

Platform Widget Extended props add...
Material IconButton material: (_, __) => MaterialIconButtonData(...)
Cupertino CupertinoButton cupertino: (_, __) => CupertinoIconButtonData(...)

Platform Circular progress indicator

A circular looking progress indicator. Uses CircularProgressIndicator for material or CupertinoActivityIndicator for cupertino.

return PlatformCircularProgressIndicator();

Uses:

Platform Widget Extended props add...
Material CircularProgressIndicator material: (_, __) => MaterialProgressIndicatorData(...)
Cupertino CupertinoActivityIndicator cupertino: (_, __) => CupertinoProgressIndicatorData(...)

Platform Popup menu

The PlatformPopupMenu will render a using a PopupMenuButton for material or use a CupertinoActionSheet for cupertino which will display a list of actions.

return PlatformPopupMenu(
  options: [
    PopupMenuOption(label: 'One', onTap: _navToPageOne),
    PopupMenuOption(label: 'Two', onTap: _navToPageTwo),
    PopupMenuOption(label: 'Three', onTap: _navToPageThree)
  ],
  icon: Icon(
    context.platformIcon(
      material: Icons.more_vert_rounded,
      cupertino: CupertinoIcons.ellipsis,
    ),
  ),
);

Uses:

Platform Widget Extended props add...
Material PopupMenuButton material: (_, __) => MaterialPopupMenuData(...)
Cupertino CupertinoActionSheet cupertino: (_, __) => CupertinoPopupMenuData(...)

Platform Modal bottom sheet

Display the platform specific modal bottom sheet...

 showPlatformModalSheet(
      context: context,
      builder: (_) => YourSheetContent(),
    );

Uses:

Platform Widget function Extended props add...
Material showModalBottomSheet material: (_, __) => MaterialModalSheetData(...)
Cupertino showCupertinoModalPopup cupertino: (_, __) => CupertinoModalSheetData(...)

Note: Since Material and Cupertino content may be quite different it may be useful to use PlatformWidget

 showPlatformModalSheet(
      context: context,
      PlatformWidget(
        material: (_, __)  => _materialPopupContent(),
        cupertino: (_, __) => _cupertinoSheetContent(),
      ),
    );

Platform Date picker

Display either the default material date picker or use a slightly opioninated version of a date picker for cupertino which uses a bottom sheet.

 showPlatformDatePicker(
    context: context,
    initialDate: DateTime.now(),
    firstDate: DateTime.now().subtract(const Duration(days: 1000)),
    lastDate: DateTime.now().add(const Duration(days: 1000)),
  );

Uses:

Platform Widget function Extended props add...
Material showDatePicker material: (_, __) => MaterialDatePickerData(...)
Cupertino (custom) cupertino: (_, __) => CupertinoDatePickerData(...)

Note: The Cupertino popup uses a modal bottom sheet with a default cupertino date picker tumbler. If you need to customize the look then set the cupertinoContentBuilder property and return a custom content. If you create your own content builder you will need to manage the state of the date yourself. See the implementation of using StatefulBuilder or StatefulWidget to manage state updates within the example project.

final date = await showPlatformDatePicker(
  context: context,
  firstDate: DateTime.now().subtract(const Duration(days: 100)),
  lastDate: DateTime.now().add(const Duration(days: 100)),
  initialDate: DateTime.now(),
  cupertinoContentBuilder: (contentData, data) =>
      _CustomCupertinoDatePicker(contentData: contentData),
);

cupertinoContentBuilder is a builder function passing in an instance of DatePickerContentData and optional CupertinoDatePickerData. The returned widget will be a custom designed widget that you return to display within the modal bottom sheet.

Utils

Platform

You can get the PlatformTarget enum when using platform in order to know what platform is being targeted.

final platform = platform(context);

This differs to flutters TargetPlatform in that it includes PlatformTarget.web rather than needing to check for kIsWeb

Platform Widget

A widget that will render either the material widget or cupertino widget based on the target platform. The widgets themselves do not need to be specifically Material or Cupertino.

return PlatformWidget(
  material: (_, __)  => Icon(Icons.flag),
  cupertino: (_, __) => Icon(CupertinoIcons.flag),
);

Platform Widget builder

Renders a parent widget for either Cupertino or Material while sharing a common child Widget

 PlatformWidgetBuilder(
   material: (_, child, __) => IniWell(child: child, onTap: _handleTap),
   cupertino: (_, child, __) => GestureDetector(child: child, onTap: _handleTap),
   child: Container(child: Text('Common text')),
 );

Platform Icons

Render a Material or Cupertino looking icon

  Icon(context.platformIcons.book)
//or
  Icon(PlatformIcons(context).book)

View the source or screenshots for the list of icons.

Platform Theme data

Helper function to a Material or Cupertino theme data property based on the platform

Text(
  platform.text,
  textAlign: TextAlign.center,
  style: platformThemeData(
    context,
    material: (ThemeData data) => data.textTheme.headline5,
    cupertino: (CupertinoThemeData data) => data.textTheme.navTitleTextStyle,
  ),
)