No, sorry that is just a catchy title. We of course should not bottom sheet1 everything. But using it in the right context can greatly improve user experience. In this article, I will share my experience applying bottom sheet in my Android application, Materialistic:
- to deep link to a screen within the application
- to display a richer, more visual options menu
A little context here: bottom sheet is a material design component that has been officially included in Google design guidelines since August 2015, and introduced in Support Library 6 months later2, as part of design support library 23.2. What we get out of the box are:
BottomSheetBehavior: behavior for a child view of
CoordinatorLayout, which allows gestures to peek, swipe and dismiss bottom sheet
BottomSheetDialog: a dialog with bottom sheet behavior
BottomSheetDialogFragment: a very thin extension of
DialogFragment, creating a
BottomSheetDialoginstead of a standard
All we need to do to get these goodies is to declare the following dependency:
Now let’s do something fun wih it.
Deep linking with bottom sheet Activity
Deep linking has been one of the signature of the Android platform. It allows applications to declare intention to handle certain links from outside3, providing a more seamless navigating experience for users. An example is when users search for something, choose a search result, and read the result content in the application of their choice.
Traditionally, deep linking leads users to a full screen page within an application, taking them away from the current context, before returning to it upon back navigation. This is totally fine for most scenarios, but it doesn’t mean that we can’t fine tune this behavior. What if I am searching for something, peek at one result, not interested, carry on and peek at the next one, which I decide to open in full screen. Did you get the keyword? Peek. That calls for bottom sheet!
We need an
Activity to listen to and filter Intents here4. Creating and showing a
BottomSheetDialogFragment when this
Activity is created should be sufficient. But if you are one of those people who ‘nay’ or ‘mmmmmm’ when being asked about
Fragment5, or if we already have an
Activity, then we would want to make a ‘bottom sheet
Activity’ here. Well, the truth is it’s super easy to make one!
TL;DR, what we need:
- A translucent theme
Activity6, since we don’t want it to block the whole current screen
CoordinatorLayoutwhich serves as the
Activity’s content view
- A child
BottomSheetBehavior, which hosts the actual content of the
I would recommend setting
Activity’s theme, which dims the window behind the
Activity, like when a
Dialog is shown. Even though our
Activity only peeks at the bottom, it still essentially occupies the whole screen. We wouldn’t want to leave the impression that users can interact with the
Activity behind, so let’s dim it.
So far so good, we now have a bottom sheet
Activity that peeks when deep linking to:
But we quickly realize that tapping outside or swipe down peek view does not dismiss it. We need logic to handle this, by declaring a dummy view to handle touching outside and listening to
BottomSheetBehavior.BottomSheetCallback events (I’m using Java 8 lambda syntax here):
By now, we have pretty much achieved what we need. But details matter, and it shows we care about our user experience. Did you notice the strikingly bright status bar when the
Activity is in peek mode? Its color follows
colorPrimary attribute set in our theme. Easy, just set it to some dark color! But it will leave us with a dark status bar when the
Activity fully expands.
Let’s make it dynamic: we initially dim status bar when
Activity first peek, undim it only when fully expanded, and dim again otherwise. Theming status bar is not supported pre-Lollipop so we can safely ignore it if device runs Kitkat or below.
Check out our deep link bottom sheet in action:
Bottom sheet settings menu
Materialistic has a lot of settings for users to configure their reading experience. While a dedicated settings screen is useful to be the to-go page for this, more often we would want to save users a round trip to go back-forth between screens to change settings. Options menu7 is a good candidate for this. It comes with
Fragment, and is declarative via XML.
But while serving well as a place to put simple settings, its monotonous style and being tighly controlled by framework and support library quickly make options menu feel like a make-shift choice for complex or more visual settings. One would need extra logic to handle its state, e.g. load from
SharedPreferences and set checked state for a checkable group, save preferences to
SharedPreferences when an item is selected. In the end, we end up with some less than satisfactory options menu:
Now you see where I’m going with this, how about a bottom sheet settings dialog! Combining
PreferenceFragmentCompat - provided by
preference-v7 library - and
BottomSheetDialog, plus a few tweaks to make a Spinner preference8, and we can achieve a much richer settings menu, right on the same screen:
TL;DR, what we need:
DialogFragmentthat hosts a
PreferenceFragmentCompatthat hosts the view for our preferences, which is included as a child fragment of the above
- Options menu logic to open our
OnSharedPreferenceChangeListenerto react to changes in preferences
Let’s first wire up logic to show the bottom sheet settings UI.
You gotta be kidding, it’s not that easy right? Yes it’s that easy! Now what remains is to listen and react to preferences changes.
What about preferences state, e.g. initial state when open, saving from and loading preferences to UI? It should have already been taken care of by
PreferenceFragmentCompat (or our custom
Preference). And we’re done. No more painful settings. One step closer to material design heaven!
Supporting tablet users
Bottom sheets look great on phones. But when putting them on tablets, they feel stretched out, especially in landscape mode. It’s due to the high ratio between peek height vs full tablet width. Details matter, and we want our tablet users as happy as phone users. Let’s customize bottom sheet width for tablets.
By putting desired width in respective resources directory with width qualifier9, we can now specify different bottom sheet width per device width, making it much more pleasant to look at on tablet:
I’m sure there are more creative ways to make use of bottom sheet. Keen-eye hardcore Android users may notice that it looks somewhat like dialog in iOS now (minus the blurring glass background), but hell, what matters is the experience you’re giving users here. Above are 2 applications of bottom sheet I found useful for Materialistic. It’s open source as always, so check it out on Github.
To make a translucent Activity, we need to set
windowBackgroundtheme atrributes. It is important to note that these attributes cannot be changed dynamically, so one needs to explicitly declare translucent