字幕表 動画を再生する 英語字幕をプリント 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]
B1 中級 米 物質的な改善 - Google I/O 2016 (Material improvements - Google I/O 2016) 43 4 gg に公開 2021 年 01 月 14 日 シェア シェア 保存 報告 動画の中の単語