Hello.
Thank you very, very much for coming, everyone.
My name is Nick Butcher.
I'm an Android designer and developer.
And I'm here today to talk to you about the Material Design
principles, about understanding and building them.
We've got a lot to cover.
I'm going to teach you a lot of stuff today.
So let's get started.
So Material Design.
Who's heard of it?
Hopefully everyone.
So introduced at Google I/O a couple of years ago.
Right?
An amazing design system for helping you
build incredible, consistent, usable apps.
One of the things that I personally really,
really like about Material Design, and that I think
sets it apart from other design systems out there, is this.
It has these principles.
It has these kind of-- it strives
to go beyond what a lot of design systems do out there.
It tries to answer the question, what
is the material that your UI is actually built out of?
It provides these guidelines which describe the world
that your UI lives in.
It's kind of like how we have the laws of physics
in the real world, which, once you understand
the laws of physics, they can be applied to other situations.
It's the same in the UI world.
If you have this level of consistency underneath things,
it means that patterns learned in one place
can be applied elsewhere.
While Material Design is very wide
ranging-- it kind of gives you a lot of patterns and components
to work with to build your UIs with-- no design system
can be comprehensive.
It can't think of every single situation, every use case
that your app is trying to solve for.
But by having some underlying principles,
some kind of consistency underneath,
if you try and stick to these, when
you solve your particular use case
it will feel consistent with the other components and patterns
out there, making for a better experience for everyone.
But the problem with the principles
is that it's somewhat abstract, I feel.
Sometimes it can be hard to understand exactly how they
apply to your application.
So I'd like today to talk to you about this.
This is an application I built called
Plaid, which attempts to embody these principles.
So by discussing some concrete examples
of applying the principles, I hope
to help you to develop a better understanding of what they are,
to understand how they can actually help improve
your application, as well as teach you
how to build them on Android.
So a couple things.
This app is completely open source.
So you can grab the source code on GitHub
or you can join-- it's in beta at the moment
on the Play Store, which you can join at that top link.
This app-- also, I want to call out-- uses a minimum SDK of 21.
It's a Lollipop and beyond app.
I did that mostly to unburden myself
from backwards compatibility, to see what we could build.
But there are efforts going on-- actually, mostly driven
by amazing third party contributions.
So there's a back port branch, which actually brings it
all the way back to API 17.
So yeah.
Let's crack on with the application.
So let's go through the Material principles one at a time,
and let's see how we can actually
make the application better, and how to build those things.
So the first Material principle is the idea
of Material tangible surfaces.
This is the idea that everything in your UI
lives within a surface.
And these surfaces can have different sizes, shapes,
and elevations, and so on.
Now surfaces really, really help you to-- they
tap into a part of your brain which recognizes that one
thing is separate to another.
We call that tangible objects.
That means you can see that a button is going
to be a tap target, or that one surface is
going to move past each other.
It's also really helpful for providing hierarchy
in your application.
We're really good at knowing that things
which are closer to you are larger or more important.
We just know this from the real world.
And you can use that in your UI to direct attention to the most
important information.
Here's an example.
So in the application, I showed some images
from the awesome show and tell site called Dribbble.
And the image is the primary focus of this application--
of this screen.
Sorry.
So it gives this big old prominent area at the top.
But once you've seen the image, you perhaps
might want to take some other action.
So there's comments or descriptions and so on, then.
I kind of want to get it out of the way,
but still have it accessible.
So here's how I do it in Plaid.
Hopefully you can see it collapses with some parallax
to keep it centered.
Then at a certain point, the image
pins-- I like to think of it-- and lifts up to let the content
pass below it.
If we were to take a 3D view of what's going on here,
it's kind of like-- it collapses to a certain point,
and then the surface itself lifts up
into a separate surface.
And there's another surface going on here.
The floating action button.
We're saying that this is the most prominent thing.
I think that liking a shot is one
of the most prominent actions I want to call out.
So having that on its own surface
which moves with certain physics and then snaps
when it reaches the bottom of that lie there,
again, helps to direct attention.
So how would we build this?
Well, I decided to use a stateless animator,
because you could imagine doing this yourself.
Listen to the scroll position of the list,
and when you reach a certain minimum height for the image,
then just elevating it.
But that would put on you the burden
of having to run an animation, work out
if the user has quickly scrolled and quickly scrolled back,
then you have to cancel it and reverse it.
Instead, using a stateless animator helps you to-- it
does it automatically for you.
So all I do is I basically set this state of pinned
to true or false, depending on how far these are scrolled.
And then just run an animation over the translation
z property, and it will produce this
lifting up and pinning effect.
I use surfaces again in the same screen
when looking at comments on a shot.
So for each of the comments in the list below,
there are certain actions you can take, replying,
liking the comment, and so on and so forth.
Rather than an alternative presentation--
it might have been to have these comments visible or overflow
items and so on and so forth.
But that would have led to a more cluttered look and feel.
I wanted this thing a bit cleaner.
So using the idea of surfaces here, I think helped.
Because, as you tap on a surface,
we have this idea that it raises up and gets
an elevation and a little drop shadow underneath.
And the comment actions reveal themselves.
So again, I feel surfaces help to make
it a cleaner presentation.
And building it was pretty easy.
There's three steps to it, which I'll walk you through.
So firstly, it's a comment-- it's an adapter at the base,
so in the list use adapter, we work out
whether we can hold onto the position
of the current expanded item.
And based on if it's the expanded one,
we just set the visibility of those little actions there.
Then in the onClick handler, we store the position
of the one you are trying to expand.
And then we use one of my favorite APIs
in Android, which is TransitionManage
r.beginDelayedTransition.
This is deceptively simple, because it's
doing lots and lots of work for us here.
So by saying beginDelayedTransition
and, crucially, we parse the whole of the list view,
rather than the individual view you clicked on.
That will then watch for any changes
to any views underneath the list view.
So that's going to handle collapsing one item
and expanding another item smoothly for us.
We then call notifyDataSetChanged,
which will then rebind both of the items
and set the right visibilities.
You notice we also set the activated state
based on whether the currently selected item's expanded.
We then just pretty simply is use a stateless drawable
for the background.
And two of my favorite attributes,
which most people don't tend to set,
is you can set this enter and exit fade duration.
So this will automatically handle
the color change for you.
So when you select an item, it fades in
nicely from the background color to a pure white,
to show it in the selected state,
or fade out the one that is getting deselected.
All, again, automatically for you.
And similarly, we use a stateless animator
again to do some translations z to lift up and out.
So hopefully you can see just-- some pretty simple stuff.
There's no major custom work going on here.
It achieves this quite smooth, nice effect,
and makes for a cleaner layout.
So I think surfaces really helped with this here.
Next up is this section of the Material spec, which I
really, really like, which is talking
about navigational transitions.
And it talks specifically about navigating from a parent
to a child screen.
And it shows this video here.
I love this idea that when you click on an item,
it lifts up out of the parent screen
and expands out to fill the screen.
I'll come back to the motion part of doing that a little bit
later on.
But part of the thing I like about this
is the idea-- this permanence idea
that the previous content is still there,
and that the new screen is lifted up
and it's sitting on top of it.
I use this idea in Plaid.
So for example, here is a grid of images we're looking at.
When you tap on one item, it lifts up.
But crucially, what I've done here,
is that when you overscroll down,
I start to translate and scale the content downwards.
But peek, and you can see the screen behind.
Again this is reinforcing this idea
that this new screen of content is sitting on top.
I feel like it gives it more of a sense of place.
You understand where you've come from.
It's hard to get lost, because it's
so continuous an experience.
So to build this-- notice also that when you try and collapse
it, it's a single gesture.
So in the content here, I'm scrolling down,
keep on scrolling from the same gesture,
leads to this backwards behavior.
It's not like you have to scroll and then
scroll again or anything like that.
It's one single experience.
And that's all built on the awesomeness
of nested scrolling.
So if you haven't checked out nested scrolling,
it's really, really cool.
So here's a-- it's a custom view I wrote to do
this, which extends frame layout.
And what nested scrolling lets you do
is listen to scroll events that the child of that is doing.
So inside the frame layout, there
is a ListView here which is sending scroll events.
And basically, you just overwrite a few APIs.
So the first one is onStartMessageScroll.
This is basically asking, are you
interested in listening to more nested scrolls.
Here I'm saying, anything that's scrolling vertically I'm
interested in, please send me more events.
So if you returned true from that one, every time the user
scrolls in the list, I'll get this onNestedScroll event.
So you can do stuff with working out
how much the ListView scrolls by itself,
but the one I'm actually really, really interested in here
is that last parameter, which is dyUnconsumed.
So that basically tells me if the List has scrolled
to the end of its scroll range, but the user carried
on trying to scroll, there were some unconsumed scroll events.
So I want to take those, and I'll then just
use set translation y and set scale
to actually translate and scale down all the content,
moving it away.
And then finally, when the user lets go, I can work out,
did they scroll past a certain threshold?
If so, I'm going to finish the activity
and run an animation to collapse it.
Otherwise, I'll settle it back into its natural position.
The final part of the puzzle here
is that the activity was sat on top of the previous activity.
And you can see through to it the one behind.
The way that you do that is you set this flag
windowIsTranslucent.
And what that means is that you're telling the system,
don't finish the previous activity.
So it'll go into onPause, but it won't actually
go into unDestroyed, because you're
saying that when the content on top is translucent,
it's going to be able to see through to you.
It's kind of like, if you showed a dialog on top of your app,
rather than showing a new activity, it won't finish you.
And then you set a semi-transparent window
background.
For those of you who don't read hex colors,
that's like a semi-opaque gray.
That's how you build it.
So that was surfaces.
Again, I think made it more understandable.
So another example of surfaces in the application
is-- this is a Dribbble profile screen.
So here I use surfaces with great prejudice
to basically show content hierarchy.
So here, when you scroll the content,
I actually made the decision to leave the profile information
statically, and have the images scroll completely on top of it,
completely in front of the content.
This is me being opinionated and saying,
I think images are the most important part of this,
and I want to direct attention to those.
And that's how you do it.
So how would you build this?
You can consider-- a frame layout
lets you overlap content.
So you might put the profile information
in one layer, then the RecyclerView of images on top.
And that's all well and good.
But what about the clicks?
If the RecyclerView's on top, how
do you let clicks pass through?
So I kind of cheat a little bit here.
So I set an onTouchListener onto the RecyclerView itself.
And then I work out where the top of the first item
is, which I've set down with some padding.
So then, if the touch point where
you're touching on the RecyclerView
is above the first item, I directly
call and dispatchTouchEvent onto the content behind.
This is the description field behind.
So that forwards on the touch event.
So again like letting the touch pass through the RecyclerView
onto the content behind.
So it lets you do this kind of layering trick.
And my last example of surfaces is--
I love the idea that surfaces, while they're
inspired by paper and things in the real world,
they're not limited to them.
I love the idea that we can transform from one shape
or object to another.
So here for example, I've got a couple
of actions which use the floating action button pattern.
And when you touch it, sometimes you
have more actions to be taken.
So if you're trying to like a shot,
and you haven't logged in, I want you to log in.
Or if you're trying to upload a new shot and a poster design
and use, you have to give details of it.
Rather than-- you could imagine a different presentation, where
you just show a new screen or just show
a dialogue on top of it, I feel that by transforming
the surface itself, it's clearer that you're
trying to act on this thing.
And it requires a second step.
I think the transformation aspect of it
helps you to have a continuous experience.
I haven't got time to show you how
I've built this particular-- shared element
transition is what it is.
But if you come to my talk tomorrow,
I actually go through it.
So that's a window into transitions.
That was surfaces.
Second principle I want to talk through
is using bold graphic design inspired
by all the great design literature out there.
This talks about using classical things like color, typography,
space, and imagery to really provide
a nice, clear, and beautiful presentation.
So in earlier builds of Plaid, I tried to use color,
like color primary and distinct blocks of color,
but I found that displaying a lot of imagery,
as well as lots of bold colors somewhat clashed.
So in the end, I ended up backing out a lot of color.
In fact, if you look at the screen here,
the only thing I'm contributing is the kind
of floating action button, that little green button
at the bottom.
The idea here being that content was the main thing.
I wanted to reduce my personality to make room
for the content to shine.
That doesn't mean you can't use color in interesting ways.
So I instead use some dynamic coloring in order
to make the app still feel alive and thoughtful.
So here for example, as you're clicking on an item,
you can see the touch response-- the touche ripple you get
is determined by the item you're clicking on.
So the gray and red one gets a nice red ripple,
and the one below gets like a bluey-purple ripple.
Hopefully that comes out.
So the way you do that is from the awesome, awesome Palette
library.
So Palette runs over an image and picks out the palette
of colors inside the image.
And one thing I want to call out is it offers this Filters API.
So Palette by default it's built for working
on landscape imagery.
So it'll actually ignore certain color ranges.
It'll never give you pure white or pure black, for example.
I actually want that in this application.
The imagery that I'm dealing with here
is actually different to the landscapes.
So you have this API to clear the filters, which
will give you a wider range of colors
that it will actually pick out an image.
Worth knowing about.
Once you have a Palette, I then have this little method
to create a ripple drawable for me.
Now, Palette will give you these named swatches.
In particular, I really want to use the vibrant color.
So picking out that red from that first image we saw
is a great way to kind of tie the touch ripple
back to the item.
So what I do is I walk through the swatches one at a time.
You have to go through them each,
because you're not guaranteed that there's
going to be a named swatch.
So for example, if I were to give a black and white image,
it's not going to be able to return
me a vibrant color from that.
So you go through them one at a time, in a preference order.
Work out what color to use, and then
create a new ripple drawable.
And then set that as the foreground onto the image
you touched on.
I actually take this idea bit further
when going into a details view of an image.
Here I am quite zoomed in.
So as I click onto each image, I want to have this immersive,
seamless feel to the application.
So what I do is I again use color picking.
I pick a color out of the image and set it
as the status bar color.
You could have achieved something similar
by using a semi-transparent, partially black, perhaps,
status bar color and having the content run behind it.
But because the detail screen is all about the image,
I wanted to overlay as little as possible
to not have anything on top of it.
So instead, I used this color picking.
But what about a situation like this?
So here's an image which is a couple of major color blocks.
If you were to run Palette over the entire image like this,
it's likely going to pick out the of purply blue
in the middle, because that's the most dominant color,
but that's not what I want.
So I don't want have this purply status bar, then
a block of white and then another purple in the middle,
it's going to look quite discontinuous.
What I really want is to run Palette
over just a subset of the image, just the top part,
such that that's going to be the best color to set it
against as a status bar.
So you could imagine a situation where
you could create a second bitmap and run Palette over that.
That's going to be quite inefficient.
Palette's already walking over bitmap.
A better thing you can do is use the Region API.
Palette here offers an API that says, only look
at this area of an image when you're picking colors
from it to consider.
So it's going to be much more efficient.
And I also want to call out the fact
that Palette lets you set the maximum number of colors
that you look at-- that you consider in an image.
Basically what Palette's doing is walking through,
trying to bucket the colors into smaller and smaller bucket
sizes until it comes out with this Palette of colors
which are in the image.
And you can control that.
So here I found setting this allowed me to pick the more
dominant colors quicker.
And lastly, you might have noticed
I'm using the awesome LightStatusBar
API on Marshmallow.
So that basically lets me set dark icons for the Wi-Fi
and the clock and the battery and so forth.
The way you do that is I basically
pick a color from the image for the status bar.
And then check if it's light by essentially
converting the RGB into HSL-- hue, saturation,
and lightness-- and then looking at that third component, just
the lightness, and seeing if it's over a certain value.
Then say, yet, that's light.
And if so, setting the status bar against dark.
So it's all about creating this immersive feel
where the content is contributing to the UI.
Next up, Material recommends using certain grids.
So here I am overlaying some of the key lines which
we worked with in Material.
And I think this really, really helps
in providing a regular rhythm to your application,
making it easier to scan it, and parse it when you look at it.
One section of the Material spec which I found quite interesting
was that it says that you should use an 8dp grid for most items,
but typography should sit on a 4dp grid.
It does this mostly by setting line height, recommending
leading or line height that you should work with,
which are all multiples of 4dp.
But unfortunately, Android doesn't offer a built-in way
and text you right now for doing that.
So how do we do that?
How do we make sure our text all sits perfectly
on this 4dp grid in order to get this nice, regular rhythm?
Just for comparison's sake, on the left
is without the 4dp base length grid,
and on the right is where-- hopefully you
can see that this is-- you might consider
it a small thing-- like maybe having type sit on the grid,
but I really think it helps the readability of the screen.
You can park, scan down it, and read it.
And hopefully it just feels a lot more regular to you.
So what we really want is to be able to specify that line
height.
So here's a style where I've set a-- specified the line height
to match it.
I would call out, especially, that I
called it lineHeightHint, rather than just lineHeight,
because with type, we all know we should
be working with SP units.
Right?
So that you can take into account
if the user has bumped up or down
the text size for their particular needs.
So I call it lineHeightHint because this lets you specify
the line height in the same units, in SP,
such that, if the user has set their text to be larger,
you want the line heights to grow with it.
Then I created a custom view, which extends text view
and does some magic for us.
First it basically takes that line height
you specified, and rounds it up to the nearest 4dp.
Essentially making sure it's going to-- the line height's
going to be a multiple of 4.
I then work out the height of the font.
And then call an API which TextView does give you,
setLineSpacing, which wants to take the line spacing
additions-- so that's the line height I want,
minus the height of the font, is the addition.
And that will give you the 4dp grid that you want.
The custom view actually does some extra stuff.
It makes sure the padding top is at the right,
so that the first baseline sits on the grid.
And it adjusts the padding bottom
to make sure the entire element is a multiple of 4dp as well.
So a bit of work, but I really think it really helps give you
this nice regular typography.
Speaking of typography, I also make
use of some of the more advanced features of Roboto.
So hopefully you know that fonts often
come with lots of variations in them.
So for example, here I'm using this small caps presentation.
And this is what they call old style numbering, which
gives you a different numbering format.
I feel that using these different typographic
variations help you to express hierarchy
and gives some visual interest to the screen.
You have more range of presenting text.
So rather than using lots of different text sizes or colors,
using different presentations like this
help you to say what information is more important,
making it easier to scan through it.
You can set these font feature settings really easily.
They use this web syntax where smcp, for example,
means use small caps or onum means use odd numbering.
There's a whole bunch of things you can fiddle with.
But I encourage you to check out the different range
of typographic options the font you're using gives you.
And while grids are awesome, I also
think it's interesting to break out of the grid.
So here, for example, we have this floating action button,
which kind of straddles this title and description field.
This breaking out of the grid draws attention to it.
But you can come into issues when you're
doing this kind of thing.
So you don't want the FAB to be on top of any text.
You don't want it to be obscuring
any important information.
So what are you going to do?
You could, for example, just add some padding
to the right, which might prevent
any overlapping of the text.
But you're going to end up with this less
than ideal presentation, where you
have these big empty spaces.
What we really want is-- my slide to advance-- there we go.
What you really want is to be able to lay it
out to the full bounds, but then kind of flow
around any overlapping areas, like this, which is what we do.
Let me go back a second.
So everyone knows that TextView doesn't have a flowing API,
unfortunately.
But hopefully you know that TextView uses something else
under the hood to actually lay out its text,
it's just called Layout, funnily enough.
But Layout got an interesting-- I'll
say static layout, particularly, which
is what's used for unchanging text-- got
an interesting addition in API 23, which is called setIndents.
So this API takes an array of ints specifying the indents
to use per line.
So we can use that API to work out
which lines of text in the title field overlap with the FAB,
and set an indent.
So on that second line, set an indent on the right, such
that we can build this kind of flowing behavior.
So create a custom view again, which
again, works out where the overlap between these two views
are.
And it calculates an array of these indents
that we want to set.
So essentially, the second line in the right index
is going to have an indent.
And then you create a layout through the Builder object
passing those indents, again, letting
you wrap the text around it.
This is kind of cool approach.
I think is quite a useful thing.
But it comes with a giant warning.
So as you can see, this extends View.
Unfortunately, TextView doesn't have a set layout method,
so you can't just create your own static layout
and pass it into TextView.
So I'm having to extend view, and then in OnDraw,
having to draw the layout on to the canvas.
So it's a pretty cool technique, but that
means you're not at TextView, so if you
have to do things like right to left support or accessibility,
you're kind of on your own there.
So great power, great responsibility.
One of those APIs.
Right.
While I'm talking about layouts as well,
one of the things I wanted to do on the grid screen
is provide a bit more visual interest.
While a regular grid is fine, I actually
wanted to provide a bit more visual interest
and highlight certain items.
So here for example, the middle image
is actually spanning two columns.
So it's maintaining aspect ratio but spanning two columns again,
to provide visual interest to certain items.
RecyclerView's gridLayoutManager makes this super simple to do.
You basically set a grid span-- setSpanSizeLookup
to return how many columns it should span.
And I basically delegate that to my adapter
which knows more about each item.
The problem with this approach is that grid layout manager
will happily leave gaps.
So if you say I want to span two columns,
but it's actually in the second column,
it'll actually just leave a gap and put it
on to the next line, which isn't what I want.
So here's a protip on how you can avoid that.
I essentially hold onto the positions of the items
that I want to expand across multiple columns.
Do some bookkeeping to basically work out where in the row
that will appear.
Because I want to span all the columns,
I know that the item has to appear in the leftmost,
in column 0-- row 0-- row position 0 in order to span,
otherwise it's going to leave a gap.
And I then essentially swap it with the next item
it could appear in in order to not leave any gaps.
I want to say that this approach has some drawbacks.
So right now, here's how it looks on a tablet.
So here I am using four columns--
but essentially, spanning four columns,
maintaining aspect ratio, isn't ideal.
It's leading to this whole thing.
So here's a sneak peek of something
I'm working on right now.
So this is a custom RecyclerView layout manager,
which is allowing me to span both columns
and rows simultaneously.
So that you can have this item which is appearing, taking up
four cells, as it were.
And other items are flowing around it.
So this will be getting pushed open source real soon now.
Promise.
And next, I'm going to talk about what you probably
guessed is one of my favorite portions
of the Material spec, which is talking
about meaningful motion.
I just want give a massive shout out, though.
It was a really, really good session last night
by John Schlemmer, talking about their recent updates
to the Motion design guidelines.
If you haven't checked it out, I highly encourage you to do so.
So the meaningful motion section talks
about using motion not just for showbiz,
but for actually guiding focus and giving
a spatial model for providing interaction cues and character.
So let's look at what these principles mean
and how they help me in my app.
So here for example, is a list of players--
a list of Dribbble users.
And when you click on one of them,
it expands out to go to a detail screen.
So again, that could have been just a new screen
with a default transition.
And Motion really, really helped the design here.
It's going a bit fast, so let's slow it down and look
at the things that's happening.
When you click on a user, first thing, I raise it up.
So it's the idea that this item is lifting out of the list
and then grows.
You see how the whole card itself grows out
from its original position, while also the image--
the main point of focus during a transition--
smoothly transitions from its previous position
into a new position.
And then finally, the rest of the content enters.
So how would we build that?
The first bit, raise on touch, that's easy.
That's my friend the stateless animator we looked at earlier.
Here we're keying on the state, if it's pressed or not pressed.
And we say we want to animate the translation z based on
if it's pressed or not.
That's pretty simple.
Next up, the expanding row.
This is a shared element transition,
using API 21's transitions API.
So there's actually two shared elements going on here.
The first one, the image, it's pretty obvious.
Right?
You say the image is here, and it's going to here,
and this changeBounds transition will handle the size
and location change for you.
The second shared element is actually the background.
So the background of the list item, I say,
is the shared element.
And I want it to transition to the background
of the details view.
And it grows out like this.
So one drawback of this approach is
that, by default, transitions will
use what's called the shared element overlay.
That means that they're on top of everything else.
Now if you put the background on top of everything else,
you're not going to see any of the rest of the content.
So we wanted the background to come in
and the content to come in at the same time.
So you actually have to turn off that shared element overlay,
using this flag in your theme.
And that will prevent that issue.
Next thing I'm going to call out is-- hopefully
you noticed it's using this arced motion approach.
So things that move linearly can often seem robotic.
Using arced motion, curved motion paths,
feel more natural and more organic to us.
This is super simple to do in a shared element transition.
You literally just add this tag here inside your transition
definition to say arcMotion, and it will
do this arced path for you.
So easy.
I love it.
And the last bit is a custom translation
which I wrote, called-- which I've called LiftOff.
Now, it's easiest to show you what this does by showing you
with and without it.
So here's two versions of the same video.
So you touch on the item-- oh yeah--
one's with, one's without.
I hope you see that.
Hopefully you can see there that, as they start expanding,
one of the items is casting a shadow,
using my custom transition, it's a classic shadow,
and one isn't.
So it's not [INAUDIBLE].
It's a bit easier to see on the way back, actually.
This is because, if you haven't seen,
transitions all happen in the destination window.
They're all happening in the details view.
So in the details view, the background
has no elevation or anything, it's the background.
So it, by default, won't cast a shadow.
So by running a custom transition, which will actually
set some elevation on the background
while it's transitioning, we can actually cast this shadow.
This might seem-- maybe I was being a bit too nit-picky,
and-- does this actually add anything?
You might not see it at full speed,
but it just feels better.
It feels right.
Trust me.
This is the easiest transition I've ever written in my life.
You basically pass it in at a value elevation
to use during the change.
And you just animate the translations z property
to start off from the elevated value and settle down back to 0
over the course of the transition.
And I actually run this for a slightly longer duration
than the-- let me see if I can get this to show-- I run it
for a slightly longer duration than the ChangeBounds, as well.
So you see it actually changes into position
and then settles down.
So it gives this effect of lifting up
and growing and collapsing and setting back in.
Last piece is that the image is moving upwards,
so I wanted the content to enter upwards with it,
to make it this kind of cohesive experience.
So rather than the image coming in and the content just popping
in, I wanted it to like feel like it was all
moving in the same path.
So mostly it's handled with this window content transition.
So there's both a shared element transition
and the window content transition on the same screen.
And it's just using this slide to slide
the content in from the bottom.
But as we saw before, this screen
is some static content and then a RecyclerView of items.
So that led to this weird feeling
where some of the content would slide in,
and then the RecyclerView does a network request,
gets the images, and then they just load in,
which wasn't ideal.
So instead, I wrote a custom item animator
for the RecyclerView, which will then animate the items
in upwards, as they load.
So just extend the default item animator that RecyclerView
gives you for free.
And I overrode the animateAdd method, where you basically
do some set up.
You basically translate it downwards and set it
to invisible.
And then when you run the pending animations,
you animate those properties back to their natural place.
You fade it in, and animate it upwards, and do some stuff.
So that was one transition.
Another transition I want to talk about is the search view.
So this is what searching looks like in Plaid.
And again, there's quite a lot going on here.
So let's slow it down and step through it a little bit.
Firstly, when you come into the screen,
I expand out this scrim, and then
also do an animation on the icon itself
to change it from the search icon to the back.
And then fade in the search field.
And then, once you've done a query, we load in the results.
So the goal here is really about directing attention.
So when you touch on the search thing,
I want it to feel like this transient experience.
So that it's just coming in transiently
over the top of the content, which
is why I do that scrim coming in slowly and gently.
But the next thing I want you to do
is to enter a search query in the search field, which
is over on the left.
So that's why I feel the animation over from one side
directs your attention to what you have to do next.
Similarly, once you've entered your query,
you can see that the container expands
downwards to make room for the search results to come in.
Again, that's priming you for the attention.
For you to say, OK, I've done that.
Now I'm looking down here to where
the content's going to be.
It's all about directing your attention.
Like the previous screen, this is obviously doing network.
Right?
It's going out, hitting an API with a search query,
and getting content back, and loading the images.
I feel like this animation also helps hide
some of that work going on.
It's distracting.
The animation stretching downwards
is buying time while I'm doing this networking
and coming back to make it feel more responsive than it,
perhaps, technically is.
Now I'm not going to go through every single step
of this animation, because it's using a lot of the principles
we've talked about before, using animators and so on.
One thing I do want to focus on is on the icon animation.
I feel like doing the icon animation,
as well as directing attention, it also is a playful element.
It embodies some character to the application, I feel.
I also have to call up some credit
to-- I was inspired to build this animation from something
I saw on Dribbble.
So it feels quite apt.
A dribbled line referencing Dribbble.
Anway--
How would we build an animation like this?
So this is a animated vector drawable.
So hopefully if anyone here has worked with vectors,
you know that you can basically draw lines and fill paths
and so on and so forth.
But not many people, I think, know about the trim properties
you can set on a line.
So here's a line, which is stroked--
which goes from left to right.
And you can set these trim properties,
which basically say how much-- which portion of the line
you draw.
So if I set a trim end of 0.75, it means from 75% of the way
to the end won't be drawn.
And similarly, if you set from trimStart of 0.5, then
the first half won't get drawn.
So knowing how that works, we can
see this is actually just four lines.
So there's one line which joins at that stem, as I call it.
And there's two lines for the arrowhead
and one line for the circle at the top.
And all we do is we animate the trim start
and end values in order to get it to trace out this animation.
So the arrowhead and the circles are going to go completely,
clipping it to make it hide.
Whereas the stem thing-- part of it's always on screen.
We never actually trim the whole thing, as it were.
It just animates between the two states.
Notice also that the stretching out of the lines.
As it stretches out, this is really, really
easily achieved just by setting different durations
for animating the start and end.
So here's how you build it.
So this is one vector drawable.
Like I say, there's four lines.
So each of these path objects is a line.
So it has a name, so you can identify it later on.
And a couple of protips for building
these things I found really helpful
is to create a resources file, like a regular resources file
that you put your strings and ints and stuff in.
And reference that and put the paths and the fraction
of the trim values in that, because if you're
going to refer to these a few times,
it makes it easier to only have it in one place.
And then you define object animators
for animating each of those properties.
So here's one where we're animating the trim start
and end.
And then here, referencing out to those fractions
that I want to trim to.
And again, this is where setting a different duration
allows you to have that stretching out and coming back
together feel really, really simply.
Then the last piece of the puzzle
is the animated vector, which pulls together
the drawable and the animator.
And says, what to run it on.
So here you identify it by name.
So on that stem, run this animator.
And then finally, to use it, you just load it as a drawable,
set it on ImageView and call start.
So hopefully you can see, maybe a bit of effort,
but I think worth it for the quality of some character
to the application.
So I want to call out-- this is the way
to run an AVD for a one-shot type operation,
just to run the animation.
But a nice way you can do it is often to do state changes.
So for example, here is when you like
or unlike a shot on Dribbble.
Basically you have animations between those two states.
So when you like it, it's basically--
there's two versions of the heart.
There's a stroked version with a filled version on top,
and then you apply a clip, which you
animate the clip up and down, which
gives you this filling up.
And unliking is basically, two paths and you just
rotate and fade them, and then do the the trim line thing.
That's a fun little animation that you can write.
But Android offers you this animated selector,
which makes it way easier.
You don't have to manually run all these animations
all the time.
It's a bit like a drawable selector.
So you have states like, for example, the FAB
is just checkable.
So when you press it, it's state checked.
But the animated selector, unlike its regular selector
cousin, lets you define a animation
to run when moving from one of these states to another.
So when it goes from checked to unchecked,
it will run that animated vector drawable, the avd_heart_break.
And you'll get that nice little animation.
So here's just a few more examples of where
we've used little animations.
I really, really, really believe that these
are a real opportunity to bring character and whimsy
to your application, and make it more fun to use,
have more personality.
You might think, are these necessary?
Are these strictly necessary to make your application
functionally good?
Probably not.
But I really, really think it's worth it.
And I encourage you to look into using it.
And they're also really, really fun to write.
So that's it.
That's hopefully given you a appreciation of the Material
Design principles.
I really feel that they've helped
make my application better.
The purpose of this talk today wasn't
to say you should all copy over the code from my application
and put it into your applications.
[LAUGHTER]
Although you can, it's open source.
What I really want to encourage you to do is to see it's
worth it.
I think it's worth putting in the effort of going
the extra yard, the extra mile to really bring
some quality, some character to your applications.
And go out and make something which is awesome.
There's a few links to follow up.
Again, you can get the source code or you can join the beta.
There's also an awesome code lab for anyone
wanting to get their hands dirty with some Material Design
goodness.
And always, you should subscribe up to Google Design.
And that is it.
Thank you very much.
[APPLAUSE]
[MUSIC PLAYING]