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 ofCoordinatorLayout
, which allows gestures to peek, swipe and dismiss bottom sheetBottomSheetDialog
: a dialog with bottom sheet behaviorBottomSheetDialogFragment
: a very thin extension ofDialogFragment
, creating aBottomSheetDialog
instead of a standardDialog
All we need to do to get these goodies is to declare the following dependency:
app/build.gradle
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 Fragment
5, 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
Activity
6, since we don’t want it to block the whole current screen - A
CoordinatorLayout
which serves as theActivity
’s content view - A child
View
/ViewGroup
that hasBottomSheetBehavior
, which hosts the actual content of theActivity
I would recommend setting backgroundDimEnabled
in 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.
values/styles.xml
AndroidManifest.xml
layout/activity_user.xml
UserActivity.java
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 Activity
/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:
- A
DialogFragment
that hosts aBottomSheetDialog
- A
PreferenceFragmentCompat
that hosts the view for our preferences, which is included as a child fragment of the above - Options menu logic to open our
DialogFragment
- An
OnSharedPreferenceChangeListener
to react to changes in preferences
Let’s first wire up logic to show the bottom sheet settings UI.
layout/fragment_popup_settings.xml
PopupSettingsFragment.java
ItemActivity.java
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.
ItemActivity.java
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.
values/dimens.xml
values-w820dp/dimens.xml
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.
-
Bottom sheets - Google design guidelines ↩
-
Intents and Intent Filters - developer.android.com ↩
-
Allowing other apps to start your Activity - developer.android.com ↩
-
To make a translucent Activity, we need to set
windowIsTranslucent
andwindowBackground
theme atrributes. It is important to note that these attributes cannot be changed dynamically, so one needs to explicitly declare translucenttheme
inAndroidManifest.xml
↩ -
Providing Resources - developer.android.com ↩