Placeholder Image

字幕列表 影片播放

  • 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]

Hello.

字幕與單字

單字即點即查 點擊單字可以查詢單字解釋

B1 中級 美國腔

材料改進--谷歌I/O 2016 (Material improvements - Google I/O 2016)

  • 43 4
    gg 發佈於 2021 年 01 月 14 日
影片單字