A Truly Responsive Design

This is an introduction to a new series of articles about responsive material design patterns. In every post, I will focus on one set of screens, containing popular navigation elements as well as a collection of content items.

Since I remember, tablet layouts on Android were neglected and underestimated. There is a myth, it’s not worth investing time and money in tablet optimisations. In this series, I want to show that with a proper altitude, you don’t need to do much to create beautiful interfaces that scale smoothly from narrow mobile to wide desktop. But first, let’s setup some basic concepts on top of which next posts will be written.

Your App is a freeform window

I think this is more important now than ever. The new version of Android brings multi-window support which means a user can adjust width or height of your App window freely. The App can also be installed on Chromebook. In this case right now the size of App’s window is limited to few hard-coded values, because the new Chrome OS integrates Marshmallow API, but in next iteration, when they move to full Nougat API, user will be able to change window’s size smoothly at runtime, as it can be done on any windowed OS. You can find more about it in this year’s I/O talk “Bring Your Android App to Chrome OS”. Well, I want to be prepared for it, and so should you!

What does it implicates, an Application shouldn’t rely on values-landscape, values-large, values-large-landscape, or even newer approaches from sdk13 like values-sw600dp (smallest width). If it needs to load different resources based on window width, use values-wXXXdp, if based on window height, use values-hXXXdp.

But there are already views like Toolbar in the system’s framework which relies on this non-flexible values.

For example action_bar_content_inset_material:

core/res/res/values/dimens_material.xml:
    <dimen name="action_bar_content_inset_material">16dp</dimen>
core/res/res/values-sw600dp/dimens_material.xml:
    <dimen name="action_bar_content_inset_material">24dp</dimen>

or action_bar_default_height_material:

core/res/res/values/dimens_material.xml:
    <dimen name="action_bar_default_height_material">56dp</dimen>
core/res/res/values-land/dimens_material.xml:
    <dimen name="action_bar_default_height_material">48dp</dimen>
core/res/res/values-sw600dp/dimens_material.xml:
    <dimen name="action_bar_default_height_material">64dp</dimen>

Let’s step back for a moment and imagine we have this layout to implement.

exmple

It’s a very simple example but illustrates the problem very well. We can see a well-crafted layout, showed on mobile and landscape tablet. But in reality, there are so much more configurations that developers need to take care than this two.

If we follow the Toolbar resources pattern we could add resources for content_keyline (left margin for toolbar title as well):

main/res/values/dimens.xml:
    <dimen name="content_keyline">72dp</dimen>
    <dimen name="horizontal_margins">16dp</dimen>
main/res/values-sw600dp/dimens.xml:
    <dimen name="content_keyline">80dp</dimen>
    <dimen name="horizontal_margins">24dp</dimen>

and two layouts respectfully for list container, and list container with detail container on the right:

main/res/layout/activity_main.xml:
    // single-pane layout
main/res/layout-sw600dp-land/activity_main.xml:
    // two-pane layout

The result will look exactly like the mockup we saw before. But I propose a simple responsiveness test, that handles configurations in between.

  1. Start with mobile layout and shrink height to about 300dp.

shrink

At this point height of toolbar shrinks too. It happens because the width of the screen is bigger than height. That means, we are actually in landscape mode, and App is taking values from values-land folder.

2. Expand width of the screen to about 900dp.

expand-right

Even the width is appropriate to call it a tablet-like, the resources are still taking values from folders: values-land and layout. The width is still bigger than height, and to reach the next breakpoint we set, one of screen metrics needs to be grater than 600dp (sw600dp — means smaller width).

3. Expand height of the screen to about 640dp.

expand-bottom

This is the proper tablet layout, all margins values are taken form values-sw600dp folder, and the layout from layout-sw600dp-land folder as our smaller width (height in this case) is bigger than 600dp, and width is still grater than height, so the -land suffix is in use.

4. Shrink width of the screen to 360dp

shrink-left

We are back where we’ve started.

I hope right now you get the idea how different values from resources folders are used if you treat your app as the freeform window. The worst things happen in step number 2. If the two pane layout is simply moved from layout-sw600dp-land to layout-w840dp directory, margins and keylines values for bigger screens are moved to values-w600dp the result would be much nicer.

main/res/layout-w840dp/activity_main.xml:
    // two-pane layout
main/res/values-w600dp/dimens.xml:
    <dimen name="content_keyline">80dp</dimen>
    <dimen name="horizontal_margins">24dp</dimen>

expand-right-nice

let’s move to another concept — breakpoints.

Define breakpoints

To maintain the most fluent experience, layout should have as few breakpoints as possible. Probably one or 2-3 at the most. There are already some points defined (as for example mentioned earlier Toolbar) so it’s a good idea to take it into account. Take also a look at a table about breakpoints created by Google.

The first good candidate is 600dp wide. At this point basic 16dp horizontal margin shifts to 24dp. The 72dp shifts to 80dp. The height of Toolbar also changes from 56dp to 64dp. If we are changing these few things, we could also add some more paddings and adjustments in other places of the screen. But it’s not a good idea to introduce a two-pane layout yet. This is more suitable for the next breakpoint.

The second candidate for a breakpoint is a value bigger than 10-inch tablet portrait and smaller than 7-inch tablet landscape. So more or less value between 801dp and 960dp. This is the place where can fit both summary and detail content.

The last breakpoint candidate will be suitable for really large screens, probably for laptops in full-screen mode. The value should be at least 1280dp.

Define max width

Even between breakpoints views should define a maximum width of themselves. This approach will guarantee more polished look in cases harder to define. When a layout comes closer and closer to its next breakpoint, all elements start to look more stretched, loosely spread across too large canvas.

To sum up

This article is just an introduction of a few technics on top of which next ones will be written. The following weeks you can expect examples or inspirations of screen sets with navigation that work nice together as well as full implementations on github.

If you liked this article, maybe you will also like the next one. Consider subscribing to the newsletter to be notified.