This image here for live previews of this article’s link

Please note:

This article assumes the reader has a working knowledge of Flutter, such as how to use basic layout widgets (like Rows and Columns) and basic visual widgets (like Buttons, Icons, etc.)

Introduction

In the late fall of 2017, when I started making apps, it was because I personally needed to accomplish a very specific task and I wasn’t happy with the options that were available to me. I remembered learning the basics of making an Android app from my college days, and I set out to make myself an app. Later, in the fall of 2018, I recreated that app with Flutter. I have artistic tendencies, so I carefully considered how to design the UI of my app to look as nice as possible with the Flutter knowledge I had at the time. I also wanted to make sure I designed the app to be as efficient as possible. I didn’t know it at the time, but that was the concept of UX.

In every project I have worked on since, and as my knowledge has grown, I have worked hard to make sure I make create beautiful interfaces for my apps and efficient experiences to go along with them. This article will cover how to accomplish these goals using Flutter.

Creating Efficient UX

As we know, Flutter makes it possible to easily and quickly make great looking user interfaces using the built in Material and Cupertino widget libraries. This puts us at a great starting point. In this guide we will be using the Material widget library.

Getting Started

When starting a new Flutter project, I usually do a few things:

Remove all of the sample code from the default Counter app that gets created for the project Ensure that I add a number of Flutter package dependencies that I anticipate needing before I even run my app. This allows me to start coding more quickly. Optionally, I will create a `library.dart` file in which I will export all my dependencies. This allows for cleaner code within my widget files (I don’t like tons of imports in each widget file). For smaller projects I usually won’t do this, but for larger ones I will. If I haven’t already, I determine if my app will have multiple screens or if it will be a single-page app. If there will be more than one screen, I like to create directories within my `lib` folder for each screen, and create the relevant widgets for those screens in the appropriate folders. (As you can tell, organization is pretty important to me) Started coding up the visual elements of the app. It is this step that is the most relevant to this guide.

I like to make my apps as clean looking as possible. Cluttered interfaces irritate me, and as I have ADD it makes it more frustrating to focus on whatever task I’m doing. As such, I spend some time thinking about which visual elements will translate my vision into reality at the bare minimum. We want our users to be able to do what they need to do without getting confused or overwhelmed.

At this stage I don’t think much about color or style, I just think about what I need to see and do. I’ll start coding up some widgets to bring my vision of the UI to life. While I do this, I’m constantly turning over various questions in my mind, such as:

Are important action elements within one handed reach?

How many taps or screens will it take my users to accomplish something? (This can be as simple as moving from one screen to another)

How intuitive is the UI? In other words, how easily can my user figure out how to do stuff in my app?

Let’s address these questions.

One Handed Reach

This is an important idea because our phones are real big these days. It can be uncomfortable to have to reach to the top half of the screen if you are using your phone with one hand. A perfect example of this is something I do every night: due to my ADD I find it hard to fall asleep; my mind races through a million things and I end up feeling pretty stressed out. I therefore use my phone in bed, while lying in a comfortable side position, so that I can direct my focus towards one thing. This helps my drowsiness to overtake me, and I usually am able to fall asleep in a reasonable amount of time. Now, the phone I use is a Galaxy S10+, which is pretty monstrous in a situation like that. Reaching up to the top half of the screen is pretty annoying. Thankfully, the app I use in this situation is quite well designed (Relay for Reddit), and Samsung includes some helpful one-handed features built into the phone.

We can see that it is important to allow for one handed use. Now, how do we accomplish this in our apps? Well, we take a look at the different functions of the app and ask ourselves which widget would best help us. For example, if we want to add some action buttons to our AppBar, we can consider not using an AppBar at all and instead using a BottomAppBar. For situations where the user would need to add information to a form, or perhaps toggle some app settings, we can consider making those widgets more bottom-oriented.

How Many Taps/Screens?

The more taps the user has to make in order to accomplish a task, or the more screens the user has to move through, the less efficient the app is. For forms, we can consider paring down the amount of information we need from the user, as well as making sure users can move from field to field without having to close the keyboard and tap on the next field. For onboarding, we can consider reducing the process or even remove it entirely — remember, if our interface is intuitive, we may not need to explain how to use it in an intro. For signup screens, we can make use of existing login/registration API’s, like Google Signin, to let our users login and register. We can also make use of caching so that the user doesn’t have to authenticate every time they open the app (securely, of course!); you see the point. We want to streamline actions and processes as much as possible.

Intuitive UI

When designing a UI, it is important to do so in a way as many people as possible could figure out how to use it. This could be anyone — someone who doesn’t speak the language you use in the app, someone who might not be able to read, or people who might not be as proficient with technology as others. There are a number of ways to achieve this:

Use the most accurate iconography you can.

Use the `tooltip` property on widgets such as `IconButton` and `FloatingActionButton`, or the `Tooltip` widget for others, so that if a user long-presses a button you can show helpful element descriptions. This will work especially well for desktop and web applications as you can show a tooltip if the mouse hovers over a particular element.

Add prompting text to buttons when doing so won’t clutter the UI — `FloatingActionButton.extended` is a great example.

Make sure any text is clearly visible and has good contrast with its background color. This is a bit harder, as you want people with poorer eyesight to be able to read your text, but you can’t make it too big or it starts to crowd other elements of the app. You’ll have to play around with font size and/or bolded text in order to find a good balance.

Give screens and content areas titles when appropriate — sometimes this can be a static text above content at the top of the screen, or perhaps a centered text if a `ListView` that may contain information is currently empty.

Make use of `CircularProgressIndicator` if you are awaiting a Future or a Stream — if the user doesn’t know that something is loading, their opinion of your app is likely to decrease.

Make use of `ModalBottomSheets` and `Dialog`s for certain situations like displaying extra information or showing certain settings.

Styling the UI

This is where things start to get more subjective. Things like color and font start to come into play, as well as branding. As such, I’ll just walk through my own style.

The GroovinChip UI Style

I’m a big fan of the Material Indigo color pallette, so I’ll always set the following in my `MaterialApp`’s theme:

`primaryColor: Colors.indigo`

`accentColor: Colors.indigoAccent`

I, like many others, am not a fan of having my eyes assaulted with blinding light, so I always include a dark theme option (unless I only ship a dark theme), so I will make use of the DynamicTheme package for that (fingers crossed it gets updated for desktop and web in the near future).

I prefer minimalistic and clean UI. This, as described in the UX section, is easier on the eyes and is also more intuitive. When it comes to color preference for the canvas background, I prefer to stick with the default slightly off-white canvas color for a light theme, and the default canvas color provided by `Brightness.dark`.

If this seems similar to Google’s Material Theme, you’re correct; my style is heavily inspired from theirs.

For fonts, I like to use a Sans font. Simply taking a walk through Google Fonts usually provides something satisfying.

I’m a big fan of rounded ModalBottomSheet, so I’ll use the very convenient RoundedModalBottomSheet package for this. I use these to display user account information, various app options, the app’s version number, and some developer contact info. Not all at once, necessarily, but often a combination of most of those.

I generally avoid using `BottomNavigationBar` and `TabBar` because for some reason they just look stale to me. If I absolutely need to use a `TabBar`, I’ll browse pub for something fancier than the default `TabBar`. If I need horizontally-paginated screens, which I usually don’t, I will likely come up with a solution that involves having a `Row` “docked” to the bottom of my `Scaffold` body via the appropriate layout widgets (usually `Column` and a couple of `Expanded`) and the `MainAxis.spaceBetween` property of the `Row` to put two `RaisedButtons` on the right and left ends of the row, and a custom page indicator of some sort in the middle. This is only one approach I’ve come up with, and I’m sure there are more clever and better looking ones out there. I’m always on the lookout :)

For items in a `ListView`, I’m partial to `ListTile` as well as my own custom `GroovinExpandedTile`.

For `InputDecoration` for `TextField`, I like to use `OutlineInputBorder` with a circular radius of 8, and I like to use `labelHint` and `prefixIcon` for more style.

I like to use `BottomAppBar`s and dock `FloatingActionButton.extended` to them for things like Add/Save buttons, usually with an icon. I like to put an `IconButton` at the left of the `BottomAppBar` to implement the “back” functionality provided automatically by a regular default `AppBar`.

I like to label the top of my screens, and I’ll do so in one of two ways:

An `AppBa`r with no elevation, a `backgroundColor` of `Theme.of(context).canvasColor`, a `centerTitle` of `true`, and an `automaticallyImplyLeading` of `false`.

A `Row` at the top of a `Column` with a centered `Text`

For `DropdownButton`s, I like to use my custom `OutlineDropDownButton` so they match the rest of my `TextField`s.

I like to use the outline variants of Material icons. I use the material_design_icons_flutter package for this as it is usually up to date with the latest icons from both Google and the community.

…and there’s probably more that I’m not thinking of, but that covers quite a lot.

Sample Images