Flutter Responsive UI in Practice

Hashem Abounajmi
8 min readSep 29, 2022

--

We are going to practice Responsive UI in flutter by partially cloning Apple ID dashboard and after clone, final result will be this:

Apple ID dashboard clone in Flutter

you can view apple ID dashboard from: https://appleid.apple.com/ and check how it changes when you resize the browser.

Part 1 — Responsive UI

Responsive UI means it changes according to device screen size. we categorize screen sizes to: Desktop, Tablet, and Mobile => Large, Medium, Small. these are common sizes. if you want to add more screen sizes feel free.

Screen Sizes

1- Download Starter Project

checkout starter tag by running

git checkout tags/starter

I have created some basic pages and we start by making home page responsive. look through the code to get know it.

Overflow UI

In order to make it responsive we need to update the UI for tablet and mobile, so when screen size is tablet it should show side menu and on column right side cards, and in mobile screen it should hide side menu and shows only card. Look at your apple ID dashboard and see how it changes when you resize the browser.

First we need someway to detect screen type:

We check if screen size above 1100 its desktop, between 740–1100 is tablet and below 740 is mobile. this numbers are not rigid and I have set based on how apple ID dashboard reflects to screen resize.

Replace home_page Row widget with below:

We hide SideMenu when screen size is mobile.

Now lets make Sign-In and security page responsive. it should shows cards in single column on mobile.

Is there anyway to pass device specific layout and handle the rest to Flutter? 🤔

We should tell Flutter what we want. how its doing we don’t care now. as Widgets are declarative UI elements.

Lets update our Responsive class and convert it to Widget:

Replace SignInAndSecurityPage child with:

_BelowDesktopLayout is passed for both mobile and tablet, because we display cards in single column in mobile and tablet. Do the same thing for PersonalInformationPage .

We made our UI declarative, we pass screen specific layout to Responsive widget and how its going to do it is under the hood!

Let see what we have now:

1- You pass different layouts to Responsive widget based on screen complexity or 2- show/hide some widgets regarding to screen size.

So thats the whole UI responsiveness in Flutter. its all about adding breakpoints. YOU DON’T NEED ANY FRAMEWORK.

Read more in Flutter Docs to get familiar with Responsive UI widgets :

Creating responsive and adaptive apps

Responsive Alert Dialogs

Now we want by tapping on a Account Security card, display an alert dialog and on mobile layout display as full screen page:

Responsive Dialog

Open signin_and_security_page.dart file, find Account Security cards in all layouts and add onPressed: () => onCardPressed(SignInSecurityCardType.accountSecurity)

then add onCardPressed property to all layouts:

Then add below method in _SignInAndSecurityPageState

Above we are checking tapped card type and display right modal accordingly. we are only handling the case for accountSecurity for simplicity.

Then referencing the above method in layouts:

Now, when you press Account Security card, an alert dialog will be shown.

We are using ShowDialog to display modal overlay, which overlaps all visible widgets. ShowDialog internally uses PopupRoute to handle stack of overlays and their animation. Open Dart Dev Tools and investigate the widget tree:

Our CustomModal is an overlay on top HomePage, with same parent: MaterialApp.

Read More: Overlays in Flutter: Getting Started

The shield Icon is black! lets make it blue by updating the app theme:

In order to open modal as full screen on mobile and animate it when changing browser size, I have created an special widget named AnimatedLayout that accepts initial and final widgets animates the layout changes between them. its a modification of Hero widget instead of animating on route navigation, it does the transform when AnimatedLayout state changes. Open modal.dart and update build layoutState:

AnimatedLayout widget abstract all complexity of animation for you. it just transform the changes. how it does? doesn’t matter. Thats the power of Declarative UI.

Part 2- Navigation

For navigation we user go_router package which leverages Flutter Router api to provide url based navigation. so as we navigate inside the app, it reflects in the browser address bar and by typing in the address bar it directly shows the target page.

add go_router: ^5.0.1 to your pubspec.yaml.

Create a folder named router and add a file named routes.dart . let’s define the routes:

These are list of routes or destination the app can navigate.

now add below code inside routes.dart file:

We have defined a list of routes and initial path. so when you open the app in browser it should show the home page. but apple ID dashboard default path is: /account/manage/section/security so if you look at the first route, you see we redirect to right path.

Then we have defined a route named home reads the passed route parameters and then convert it to proper MenuItemType and returns the HomePage.

Now update home page side menu with:

So here is this; when a side menu item gets tapped we navigate to specific tab by passing target route name. I have differentiated MenuItemType from Routes. because they full fill different things, one SideMenu and another one Route. even though I have used almost similar keys. as you look carefully again we have not used any string comparison. if you mistype an string, then connection is broken!! be care-full to not use strings and use compiler features to catch erros during compile rather than runtime.

But how home page is changing the pages? 🤔

One of the common layout widgets in Flutter is IndexedStack, that shows a single child from the list of children. so by selecting an item we rebuild the home page with selected tab and it shows selected page, which uses IndexedStack internally.

Update your main.dart with below:

We are passing AppRouter.Router as MaterialApp router configurator. so simple.

Now lets see the final result:

Nice 👏

checkout responsive tag to see current progress:

git checkout tags/responsive

Part 3- Drop Down Menu

Now we try to clone Apple ID Dashboard Drop Down Menu. user needs a way to navigate between pages. We replace side menu with a drop down menu in mobile screen:

Apple ID Drop Down Menu

Final result:

Apple ID Drop Down Menu Clone

We will exercise our brains to visualize animated UI layers.

First I designed the drop down menu page in Figma then I used a Figma plugin named AEUX to convert Figma design file to After Effect composition. you can not design UI in After Effect.

⚠️ Rule number 9: use the right tool for the right job.

Then I recorded a video of Apple ID drop down menu and moved to After Effect in order to find animation timing. using After Effect helps me to easily visualize and iterate the the animation.

How we can use Flutter widgets to build the UI? if we simplify AppBar its like a Column with twoConatiners (one for menu items and one for modal barrier) which isStacked on top of theHomePage . So modify HomePage build method and add AppBar as child of an Stack widget:

Menu navigation moved to a separate method:

Animating the AppBar

Here is the timeline for animation:

Animation Timeline

In order to create a timeline we need AnimationController, and for each animation we need an Animation object which changes from 0 to 1. in order to delay animation or set it run in a portion of timeline we use Interval.

At first we want to only animate the app bar open-close:

Look at the below code and read the explanation next.

We convert the AppBar to stateful widget and mix it with a UI refresher named SingleTickerProviderStateMixin . AnimationController needs TickerProvider in order to draw the each frame of animation.

  1. Animation controller is like a video player . helps to play, pause, resume and stop the all animations in the timeline. so it expand the app bar by starting the animations and reverse them when it’s completed.
  2. Use SizeTransition to animate size of container
  3. We display modal barrier while animation is running or when its completed. if animation has reversed to its initial position, the widget is removed.
  4. Animating the modal barrier color from transparent to a shade of black.

Now lets go for animating texts:

If you look at Apple ID drop down menu, we see texts are dropping with a delay and fading in. based on my observation of captured video of original drop down moved in after effect, time line duration is 48 frame (60 per second), equal to 800 milliseconds. and menu items start after frame 10 and finish at last frame (48), each on drops with a delay of 2 frame. you don’t need to be meticulous but I wanted to replicate it as much as possible.

In order to clone drop effect, I offset each ListTile same as their height and move them back to their original position with a curve. for fade in, I use FadeTransition. my formula below may seems a little weird but the idea is simple. the point is being able to work with animations.

Replace the SizedBox with below:

checkout drop-down-menu tag to see final result:

git checkout tags/responsive

I hope you enjoyed it. if you found it useful, don’t forget 👏👏👏👏

--

--

Hashem Abounajmi
Hashem Abounajmi

No responses yet