[MUSIC PLAYING]
LIAM SPRADLIN: All right.
So I think everyone's heard about canonical layouts now.
But we're going to talk about them a little more.
I'm Liam Spradlin.
I'm a senior design advocate on Material Design.
And I wanted to do this talk with Daniel
to dive a little bit deeper, not only on the ideas
and significance behind canonical layouts,
but also how to implement them in a few different ways.
DANIEL JACOBSON: Yes.
And why should you care about this talk?
So we briefly introduced the large-screen quality tiers.
And we mentioned that the best way to achieve tier two,
or some of the biggest issues we see with apps gating them
from achieving tier two, is related to UI and layout.
And so the learnings from this talk
will help you achieve that piece of the large-screen quality
guidelines for tier two, so you can provide the best possible
experience for your end users.
There's more detail in the three tiers of large-screen quality
on Google Play talk if you want to learn more specifically
about the tiers.
But now let's get into the canonical layouts design
philosophy.
LIAM SPRADLIN: Sure.
So as you heard in the last talk,
the canonical layouts are based on what we know
about a large sample of apps.
We've developed three canonical layouts
that seek to address a lot of the broad questions
about how apps can and should adapt as you move
between different screen types and sizes,
so that you can focus on the questions that are
more specific to your product.
We're going to dive into each of these layouts one by one
and see what's going on inside each of them,
so that when you're making those decisions for your own app,
you'll be doing so with an understanding
of the layouts rationale and how all the pieces fit together.
First, we have the list detail which is, again,
a parent-child relationship, where
you have two panes that are directly
in line in the navigation hierarchy with each other.
Next, we have the supporting panel,
where you have primary and secondary pane that are not
necessarily subsequent to each other in the navigation
hierarchy, but both important and integral to one another.
And then finally, we have the feed layout,
where all of the panels are peers or siblings
in the hierarchy.
And if you've had a chance to make yourself
familiar with Material Designs' large-screen design guidance,
then you're probably familiar with the idea of layout regions
that kind of supersedes all of this.
These are containers that form a framework
for thinking about how interfaces scale
across those different screens, based
on the ways most compositions end up breaking down,
based on behavior, content, and function.
First region is the navigation region.
This contains navigation components,
like the navigation rail or the navigation drawer.
And it helps users navigate between destinations
inside an app or to access important actions.
Second is the app bar region which is also self-explanatory.
It's used to display and group components and actions
that will help users perform key tasks
or take action on elements inside.
Number three, the body region, which displays
most of the content in an app.
So this is where you're going to find most of your components,
like lists, cards, buttons, and images.
DANIEL JACOBSON: Before we get into more details about each
of the three individual canonical layouts,
we're going to go through a lot of material that's
going to vary in complexity.
The reason I'm showing this is because everything we review
is available here.
So we're going to go into development guidance,
including sample code and sample apps.
All of those are public on GitHub.
We basically tried to build the easiest way
to implement each of these.
So you can refer to those as a reference
or a baseline for your own application.
Additionally, everything is going
to be grounded in window-size class layout breakpoints.
While we do have the new utility library for Compose,
there are easy ways to implement window-size class-based logic
and views layouts as well.
And we'll review how to do some of that.
And last, but not least, before we get into the details,
don't worry about the complexity on this slide yet.
It looks really complex.
And the reason is because there are
many existing ways to build UI and layout in Android.
And we know, depending on how you built your app in the past,
we've heard this time and time again
from developers, that dictates the easiest way for you
to implement your large-screen optimized layout in the future.
And we want to make that choice easier for you.
So really only one of these green boxes
is probably going to be applicable to each
of your own applications which simplifies
the complexity a lot.
But this flowchart will help get you there.
And we'll go through each of these in step-by-step details.
LIAM SPRADLIN: So back to the list-detail canonical layout.
Here's an example.
What can we see going on here?
In this example, we're dealing primarily with the body region
that I mentioned before.
And it allocates a variable number
of columns in the layout between the list and detailed
subregions or panels.
And I say variable because as you continue
to adapt to larger screens, the two panels
may become asymmetric.
The main things to remember with the list-detail layout,
as with many layouts, are the relationships
between the primary regions in the layout
and the visual hierarchy that allows people using your app
to more quickly complete a mental model that helps
them understand how it works.
For list-detail, the relationship between our two
panels is pretty simple.
The detail is at the deepest level
of the navigation hierarchy.
And it's subordinate to the list.
In this arrangement the user is straightforwardly
navigating one level deep from the list into the detail.
This is even true for more complicated
list-detail layouts, like we see here in the reply email app.
It adds a navigation region, which
is at the top level of the hierarchy.
And it affects the entire content region
with the capability to access several different list-detail
screens, or even full-body features, like video calling.
In terms of how a user builds their mental model from this,
the list detail guides users directionally
from the navigation to the list and finally to the detail.
And it traverses that same visual hierarchy
in a visual sense as well because the detail,
which is in this case an email thread,
is the primary focus of the screen.
It's the most dynamic task.
It's elevated at a higher level than the list of emails which
is, in turn, elevated at a higher level
than the navigation region, which appears
to rest on the background.
In this way, the hierarchy is made
clear not only by directionality of the layout,
but also by visual treatments.
And from there, the normal markers of emphasis and action,
like type styles and button containment,
apply within each discrete thread or message.
DANIEL JACOBSON: So this is probably
the most common example of the canonical layouts
that we see in practice.
A lot of applications have a parent-child content
relationship.
So let's figure out how you can build it.
So trying to simplify this flowchart already,
really, there's a couple of decisions
you'll need to consider when building a list-detail layout.
And we're going to go through two of the three right now.
We're going to skip over compose for list-detail
because we're going to review it in supporting panel.
And conceptually, they're very similar.
But starting with, if you have UI content
spread across multiple activities
within your application, we now have a solution for you
to easily implement a list-detail optimized layout,
called activity embedding.
What is activity embedding?
Activity embedding is a new platform feature
supported on devices running Android 12L and later
that lets you display UI content from multiple activities
from your own application within a single task with just
configuration.
It's very easy to implement.
It's kind of the shortcut to a list-detail layout,
if you will, if you're using multiple activities.
And let's take a look.
So this is pretty much most of what
you would need to do to implement activity-embedding
within an existing application.
It's primarily configuration-driven,
meaning you just add a new XML configuration file
to your application.
And then you register that rule at runtime
with a single line of code.
We'll go into more detail in a later talk.
But, basically, what you'll do is
you'll define a placeholder rule.
And you'll create a placeholder activity.
This will be the default navigation, the first time
a user opens the application. what should you
show in the detailed pane.
And then you can configure your primary
and secondary activity-split configuration
and the split-pair rule, including
the ratio, so how much of the display
should be given to the primary activity
versus the secondary activity.
When should I actually show this split?
So what is the mean width?
In this case, we're picking the medium-width device category
of 600 DP.
And what's really great about activity-embedding
as well is with Jetpack library support
you can implement it in your existing application
with down level support.
So you don't have to fork your application
to only support this.
And the behavior is going to be unchanged on devices that
don't support activity-embedding or on devices that don't
meet the split min width value.
So basically, you're only improving the experience
on large screens without touching the experience
on all other devices.
It's a really simple, easy way to get a better experience
for list-detail applications.
You'll learn more about this in the "Do
More with Multi Window and Activity Embedding" talk.
Next is-- we're going to skip over the Compose,
like I mentioned. --a views-based solution,
say you're using multiple fragments,
called SlidingPaneLayout.
This is a Jetpack library that lets
you embed multiple fragments side by side.
And we've done a lot of the work for you
to, basically, create a more dynamic and adaptive
experience.
So, similarly, once your application
doesn't meet the width criteria, based off
of the width of each of the two fragments,
we will go back to the single-pane view
versus the two-pane view in a SlidingPaneLayout.
In addition, recent updates to the library,
now, will take into consideration a physical hinge.
So if the device has a physical hinge splitting the displays,
it will split the content over that,
so you don't have to worry about.
That does all that for you.
It's another really great way to build
a simple list-detail layout with little effort.
To use it, you basically have your two fragments.
In this case, we have a RecyclerView
with a list of elements that is contained on the left.
And then we have the details contained on the right.
And those are just the two child elements
to the SlidingPaneLayout layout in general.
LIAM SPRADLIN: OK.
Moving on to the supporting panel layout.
As you can probably tell from the name
and from this example screen, this layout
also relies on a primary and secondary panel.
But compared to the list-detail, you'll
immediately notice that the directionality of the layout
has changed.
Here, the primary focus panel, which
is still at the highest elevation,
is more towards the center of the layout
because the supporting panel doesn't necessarily
exist outside the context of the primary panel.
The primary and secondary focal points
are considered equally important and contain different content.
And both panels can scroll independently of one another.
Like before, the panel shares space
inside the body region of the layout,
using a variable number of columns.
But generally, the primary panel is going to use more space.
In terms of information hierarchy,
the supporting panel is secondary and still
complementary to the primary.
Because of the relationship between these panels,
the supporting panel can also appear at different points
on the screen.
So here we see an example on a taller screen,
where it uses the supporting panel
to show comments on a dock.
The comments are providing useful context to the dock.
But in terms of the information hierarchy of the screen,
they're still secondary to the content of the dock itself.
DANIEL JACOBSON: So just to summarize,
if you have a primary-, secondary-content relationship
within your UI in layouts, supporting panel is a great
large-screen optimized layout choice for you.
And let's learn how to build it.
So this time, we will go into Compose.
We're not going to explore all of the Compose concepts
here, just the adaptive layout piece.
You'll learn more about Compose in a later talk.
But we have a new two-pane composable
in our accompanist library that makes this much easier for you.
So what you can do with the supporting panel layout, if you
wanted to configure your own, is use
this new two-pane composable to, basically,
determine your display or presentation strategy.
So in a compact-width case-- again,
I'm using that new window-sized class utility library here.
I can, basically, split the content vertically,
50/50 in this case.
And in a medium-width case--
sorry.
There you can see the second composable.
In a medium-width case, I can split it horizontally, 50/50.
And I've got my main and supporting content.
And we'll go into a lot more detail on this one
in a later talk on "Compose--
Implementing Responsive UI for Larger Screens."
And there's another talk as well about navigation in Compose
to figure out the best way to adapt your navigation model
for these types of layouts.
Another option for building a great supporting panel UI
is using resource-qualified layouts
with a number of existing views-based layout APIs.
So for example, we'll use a linear layout API
in this example, where we have our activity main XML file that
is not resource-qualified.
This would be the default layout that
is inflated on a device, that is basically
going to use a vertical orientation
for this linear layout to, again, split the content top
to bottom.
And we'll basically set the weight equally.
So that it will be a 50/50 split.
And you could adjust this for your own app needs.
And then when we go into a medium-width layout--
note the resource qualifier here.
It's not smallest width.
It is width.
That's intentional.
And we'll talk about that in a second as well.
But in this case, I would split the content horizontally.
And, again, I can do a 50/50 split
on a typical foldable inner display.
Going back to this statement from before,
because I'm really passionate about it,
don't do isTablet, like Boolean logic.
And the reason why we don't want you
to use smallest width-based logic
is thinking about free-form windowing cases.
So on a Chrome OS device, when you
reduce the height of an application window,
it's really weird to then reduce the amount
of usable horizontal space in the application.
So if I use smallest width and I have a two-pane layout,
and I shrink the height of my window,
and then I lose the two-pane layout to a one-pane layout,
that's a really unexpected and unusual user experience.
If you're using just width as your resource qualifier,
then when you shrink the width of the application window,
you might lose that secondary pane.
And that is much more intuitive than the alternative.
So again, don't use this.
For those on the live stream, check out this "Optimizing Apps
for Large Screens--
Do's and Don'ts" talk for more on why not to use isTablet.
Going back into that, so now the expanded width layout,
we're using 840 DP as our width-based layout qualifier.
And the only thing we're changing here
is the layout weight.
So it's really just two lines of code.
The one disadvantage, and we hear this
from developers with resource qualifiers,
is you now have the same UI elements
split across multiple files.
And so the one word of caution, as well as reminder,
is if you're making updates or changes to your UI and layouts
that are resource-qualified, don't
forget to make them in all resource-qualified versions
of those layouts.
It creates a little bit of extra maintenance cost.
But the delta between each of the different files
is so small, it's generally not that hard to do the upkeep
and to keep them maintained.
LIAM SPRADLIN: OK.
Finally, we have the feed.
And from the name and its prevalence across products,
I bet you can already guess a lot of the details.
A feed is a grid layout that's composed
of a lot of distinct but related items
that are all on the same level as each other in both
the visual and navigational hierarchy.
Here, instead of just a horizontal directionality
for our app layout, we have the horizontal flavor
of the layout regions with the navigation and body regions
with a vertically-scrolling grid structure.
And since all items in the feed have similar elevation
treatment, emphasis among them ends up
coming from things like size-type treatments and color.
Here, navigation can access multiple different feed
layouts, while items in a feed are all providing entry points
to content deeper in the app.
With a feed layout, you could conceivably
allow the user to enter a list-detail
by selecting a story.
But you can just as easily provide an immersive experience
by giving body region entirely to that story.
Because of the grid-based layout,
it's one of the most straightforward
in terms of the division of space.
By using the entire body region for the grid,
it scales really easily to larger screens.
DANIEL JACOBSON: Just to recap, a feed layout is a great choice
if you have content of equal weight or equal relationships,
or maybe you want to highlight one or the other,
but generally, they are of equal importance.
And as Liam mentioned, this is one of the easier things
to think about from an adaptive concept point of view.
If you're using Views or Compose,
you're going to use respective grid-based controls.
And you're going to change the number of columns, basically,
the number of layout columns to fit
more or less content on the screen,
depending on what's available.
So let's take a look at that in action, starting with Compose,
using lazy grid controls.
So in this case, we have a custom-feed composable
that was authored which is, basically,
a fancy wrapper around a lazy, vertical grid control.
And what I'm doing to that is adding my own custom column
logic, again, using window-size class.
So my actual suites feed composable,
which is the one that you see rendered on the right,
is going to pass in a window-size class value
and then call a utility function in the application
to figure out the number of columns to display,
based off of the available space.
So in this case, in a compact-width environment,
like a typical phone, it's going to be a grid with one column
or a list of cards, if you will.
It's a very similar layout.
If it's medium width, it'll be a grid with two columns.
And then if it's expanded, it'll be a dynamic grid
that will do the number of columns,
so long as each grid column can have at least 240 DP width.
So the number of grids will grow or shrink.
And Compose APIs make that really, really easy to do.
This is what it would look like in practice,
using the resizable emulator, so if you want to try it out.
You can easily test it at runtime
and make sure that the adaptive logic is working as expected.
Taking a look at views, you're going
to use RecyclerView as your base controller.
But then you're going to, basically, change
the layout adapter based off of the available display space.
So in this case, we're going to inflate that feed-based layout.
And we're going to do some logic to figure out
how many columns to use.
This is the most naive and simple implementation of this.
If you don't need the best solution,
this is better than not doing anything at all.
You can, again, use resource-qualified values
to determine a static number of columns.
So in this case, compact is one, medium is two,
and expanded would be a fixed five.
You could use Jetpack WindowManager APIs
to get display metrics and change this in code
if you want to get more complex and advanced.
It's not that hard to do.
But the samples that we publish are the easiest possible ways
to achieve each of these layouts.
And this is really the easiest way to do it.
And then based off of those values,
you'll pass on the number of columns to your layout manager.
And we'll change to either a linear-layout manager
or a grid-layout manager if you have more than one column.
And it will result in this type of layout.
So you can see in this case, I will always
have five columns in an expanded-width layout.
The size of the columns will vary based off
of the display size.
But it will always be five.
With that, we hope you take a look at the resources,
take a look at the samples, and can
use them to build these layouts in your own applications.
Thank you.
[APPLAUSE]
[MUSIC PLAYING]