Flutter: Use Platform Widgets to Adopt Native Look and Feel
I’m not too convinced that cross-platform UI will ever be a real thing in terms of final product quality (btw, I think a real thing might be Kotlin Multiplatform logic + native UI layer), nobody can doubt that tools like Flutter or React Native are really effective if we talk about quick prototyping and deployment.
Flutter, in particular, helps a lot to deliver a good looking Material Design app with a few lines of code. But a Material app is not and will never be a real iOS app, so you need to use Cupertino widgets duplicating a lot of the code. Wouldn’t it be great if there were a package to use adaptive widgets?
Platform Widgets
That package exists, and it is flutter_platform_widgets
. You can install it easily inside pubspec.yaml
file:
The main building block is PlatformWidget
, which is a widget that is aware of the target platform look and feel.
Platform Widget package exposes many useful adaptive widgets, everything is listed inside project’s read me.
Migrate Material app to adaptive app
Let’s start with a typical Material app with a drawer and some contents below the app bar.
As you can see, this is not the correct look for iOS. Let’s use adaptive widgets inside the content.
Et voilà! Do you want a larger spinner? No problem:
Let’s try to give a more natural appearance also to the app bar.
As you can see we have lost the drawer in iOS. That’s because CupertinoApp
does not support it, so PlatformScaffold
must be instructed to keep using it in the Material environment. This is correct since the hamburger menu anti-pattern is discouraged by Apple. Instead, you would like to have a tab bar.
And… nothing happens! Platform Widget package ignored this attribute. Apparently it does so on purpose:
This library aims to provide a similar interface between ios and android.
— https://github.com/stryder-dev/flutter_platform_widgets/issues/72#issuecomment-531204229
Use different paradigms
So we have to use PlatformWidget
directly to achieve the desired result.
MaterialLayout
is a small stateless widget to encapsulate Material layout:
Please note that I’m not defining an app bar here, delegating to the real page laid out inside AppContent
widget. This widget would grow in complexity if I handled drawer selections.
TabbedLayout
is a bit more complex since defines the tab bar for Cupertino paradigm:
Please note the usage of platform-specific icons and that every tab describes an isolated navigator, which preserves the navigation stack even when user switches between tabs.
AppContent
widget now outputs a PlatformScaffold
with common parts of the UI:
Navigate to a second screen
Navigation is supported out of the box. You have just to use platformPageRoute()
in Navigator.push()
invocation:
Details
is a simple stateless widget that builds a PlatformScaffold
:
Theming
You can also specify different app-level themes:
Then you can adjust some specific colors, deeper in the hierarchy. For example, disabled tab color is not readable: