(inspiring jingle music) (scattered applause) - hello, everyone. okay, cool, the mic's working. so, yes, welcome to this talk
Android linearlayout, about efficient android layouts. if you've never met me before, i've been doing androiddrawup for about seven years, first the travel app company, the expedia,
then currently at trello. as per usual, my thing doesn't work. all right, i'm gonna givemy presentation over here. you know, you can click toengage, to rate sessions, and ask questions, of whichi will probably then answer the questions at the end if you ask them. anyways, so this talks aboutefficient android layouts, and when i was writingit, what i found that i was really interestedin wasn't so much so
the efficiency in terms of performance, but the efficiency in termsof leverage that you have as a developer, and so istarted thinking about it in the way that archimedeswas referring to, like, how fulcrums work, where,like, if you just give him a proper place to stand,he can move the earth, and so that's sort ofthe focus of this talk, is like, how to get the most leverage as a developer, becausea lot of android teams
are fairly small, and you'reasked to do a lot of things. and so in my case, itwould be if you give me a a standing desk, i willwrite you an android app, and i hope that you'renot expecting me to make any more terrible jokes this entire time, 'cause it won't happen. so, this is really just kindof a mish-mash of things, there's no narrative, soi'm just trying to cover up the fact that i have no transition here.
let's talk about viewgroups. in particular, picking viewgroups, which viewgroup are you gonna use for any particular layout,and i think the main thing is the simpler the viewgroupyou can get away with, generally, the better,because the more complex ones require a lot moremaintenance, and you can run into a lot more bugs, and soon the higher end of things, i'd say probably relativelayout'sone of the most complex.
constraintlayout is yet tobe seen, but it looks like it's probably going to be more complex than relativelayoutwhen it's finally done. somewhere in the middleof there is linearlayout, and then down there atthe bottom is framelayout, which is one my favorites,because it's so simple. and there's a lot ofother views in between, but these are the main building blocks for most applications.
so relativelayout and constraintlayout, they sort of occupy the samespace in android right now, which is that they positionviews relative to each other, and relativelayout's sortof limited in this regard, but it's what we've hadsince the beginning, whereas constraintlayoutis new and can do, like, all these amazing things, but there's some keyproblems with both of them besides the fact thatthey're fairly complex.
one of them is thatrelativelayout is fairly slow, and then the issue with constraintlayout is that it's fairlyalpha-ish at the moment. they haven't officially released it yet, so there's alpha out on mavencentral, but a few times they've completely changedthe api around, so it's not necessarily production ready. i mean, you could play aroundwith it now, and you could use it if you want, butyou're gonna end up with
some of that cutting-edgeproblems that you end up when you're trying to experimental technology. linearlayout is great,stacking views vertically and horizontally, you can distributethe weight, so this is a simple view, so rows are stackedvertically, and then also i distributed the weight between those two spinners equally. i'm actually fairly okaywith nested linear layouts as an opposition torelativelayout, and i actually,
last time i told someonethis, this was like by far the biggest question thati got, is everyone coming to me later saying, "buti love my relativelayouts, that's all i use, i was then that nestedlinearlayouts are the worst things in existence andso i can't believe that you just said that." so to head off thatquestion that i was going to be getting on the sessionsthing, is that linearlayouts
are sometimes slow. so if you use layout wait,and you nest them pretty deep, then they an getpretty slow, but that's only a sometimes thing, whereasby opposition, relativelayout always has to do twopasses, it's always slow. so the hope is thateventually constraintlayout will be our savior andsave us from the situation of having to decidebetween the two of them. but in the meantime, ithink really what's most
important is just to focus on profiling. so whatever layout that youdo end up with just turn on profile gpu rendering,and see if things are running fast enough onwhatever test device that you're using, hopefully like a really slow one. and if you've never usedprofile gpu rendering, i highly recommend googlingthat and looking into that, 'cause then youget these nice bars that
show you whether or not you're hitting 60 frames a second, andwhat sort of things you're spending too much time on if you don't. but really i talked aboutall that, so i can talk about framelayout, whichis my favorite layout in the world, because it'sso incredibly simple. all it can do is position things based on the parent bounds. so that is, you can positionthings inside the center
of the framelayout, or youcan position things on one of the eight cardinaldirections of the framelayout. wait, am i getting that right? yeah, eight. so, but there's a lotyou can do with this. it turns out that a lot oflayouts, if you just wanna have like say, a simpleprogress bar in the center of some large screen,like that's a framelayout, you don't have to doanything complicated with
relativelayout or what have you. it's also really great as asimple layout for overlapping views, so if you need twoviews to be on top of each other, framelayout is agreat container for that. it's also good for things likeclickable item backgrounds, so if you have some image thattakes up a very small amount of space, but if you wannahave multiple views that compose a single thing thatyou click, it's good to have like a framelayout as theparent of that, that can
actually have the clickdetection so when you click on it, it actually lookslike something is happening. so a good example of this,like in the trello application, is the notification barin the upper right corner. so this always present onthe screen, it's a single framelayout, and there'sa icon inside of it that, that white icon is alwayspresent, and then if you have unread messages, it'llput that little red thing on top of it.
and so, the white iconcentered and the red icon is actually pegged to theupper right corner, but then you can use the margin orto push it in so it doesn't just ram up against the sides. and on top of all of that,i can just have these views be very simply positioned,and then pair with clickable item background behindthat, so when you actually click on it something happens. another thing i really likeusing framelayouts for is
what i'm calling "togglecontainers", so if you have two different states thatyou toggle between, sometimes you just have a single viewthat you actually change, sometimes i've found itmore handy to have multiple views that you can switch between. and so a framelayout's a goodway to contain two things in exactly the same spot,and then toggle between them. so a good example ofthat in the trello app is the avatar view.
so this is whenever yourepresent a member of a card or something like that, ifthe user has their avatar seth and we wanna showthat, if they've never taken a picture, then we wannashow their initials. and so it's essentiallychoosing between an image view or a text view. littler fancier versionsof which that allow you to render a circle, butbasically lets you toggle between these two.
so the avatar view bringsup the next thing i wanna talk about, which is view reuse. we use this avatar viewall over the application, so these are just threescreens, like the trello board, a open trello card,some activity on the side, and there's actually ithink, three or four other locations we use an avatarview within the application. and so the questionbecomes, how do i reuse this in multiple placeswithout having to rewrite
the code everywhere, 'causethat would be kind of dumb. so the most obvious way is to use something called an include. so if you've never seenit before, the include tag allows you to point to adirect layout, and then it's as if that layout was justcopy and pasted into the code right there. and you can't modify muchof what you're including, but you can modify any ofthe layout params, that's
any of the things that startswith layout_, so that's a nice way to be able toinclude something that may have been may have beenmatch-paired, but you don't quite want it to be in the end. but the problem here isthat okay, you get the xml in every single location,but you don't get any of the logic. so now i have to come upwith some way to then apply like, find these particularviews that were in the
include, and then addthe logic for actually binding that to the view. so what i actually prefer these days is using custom view. so with a custom view, icall, instead of include, i actually just have theview in reference directly, and then you need to writethe actual custom view itself, but it's not veryhard, because this isn't a custom view that'sdoing custom drawing or
anything like that, it'sjust taking the place of what would have been in that include. and so with this customavatar view, i'm extending framelayout, so i'm sayingthe topmost is gonna be a framelayout, rememberi'm toggling between the two states. i've got an image viewand a text view, and then inside of a constructoritself, it actually inflates all the views that are underneath it.
so i don't need to, as aparent using avatar view, i don't have to worryabout what's inside of it. it's handling all of that for me. and then i can have thisone nice bind method where i take my member objectand figure out whether i should be loading anicon or loading the text. so this makes my life a lot easier. one thing worth notingthough, if you're using this sort of customview setup, this is like
a very hand-wavy version of what would be the included xml. but if you include thexml like this, you end up with a view hierarchythat looks like this. you wend up with anavatarview on the top, it's a framelayout, and then it inflatesanother framelayout, which then has the text view and image view. so obviously, this middleframelayout is pointless, we don't really need it,the lint check in android
is particularly harsh whenyou do this, something like "has no reason to live"or something like that, "has no reason to exist". so we wanna get rid ofthat, and the way that we do that is through a layout inflator trick. which is normally whenyou're using layout inflator, everywhere you'll see it,there'll be a third parameter there, and it'll be false. and that's because most ofthe time that's what you want.
but in this one particularcase, you want it to be true, which happens to be the default. and when it's true, whathappens is that the xml that's inflated triesto attach itself to the view group that you passedin as the second parameter. in this case, it's this. and then in the xml, ifyou use something called the merge tag instead of aframelayout, what happens is, it tries to thenmerge these views into the
parent view group without any interstitial frame layout. and then so you end upwith the hierarchy that you actually want no unnecessaryframelayouts involved. a third view-specific pieceof advice i had to do is with custom drawing. so this is useful in casesof, particularly complex views, you can can savea lot of time by just drawing yourself insteadof trying to figure out
how to wedge theseviews into what you want it to look like into normal views. so a good example of thisin the trello app is the labels, so there's thesegreen and blue and red and yellow and purple labels that are on these cards. so when we first had thetrello app out, there was like six colors, and that wasit, that was the most you could apply to any card.
and whoever was workingon it back in the day did not know about customdrawing, and decided that those would just be six views. so that meant that everysingle card potentially have six views inflated. but then later on, trellochanged this, that it allowed any number of labels to bedrawn, so then you could end up with this nightmarescenario, where every single card could have dozens oflabels on them if someone's
going really crazy. and then we were talkingabout recycling those views, it just gets really slow,and if you talk about putting something like thison a tablet, it gets really, really slow because youcan see even more cards, and it's rendering even more views. so it was much simpler, thento just take all of those views that were beingrendered, and instead, have one custom view that drawsreally simple shapes.
so there's sort of two stepsto it, and custom views used to be very intimidatingto me, i used to be very scared of custom views,'cause i thought they looked really hard, but they really are not. and the first step is justtelling the custom view how big it should be. that is, how much spacedoes it need to take up? 'cause i have my labelview, which is really nice, but no one knows exactlyhow much space it's
going to take up. so on measure is what youuse to tell any parent view group how much space you need. and it turns out, a lot ofthe times, you can actually skip this whole step entirely. and the reason i say thatis because in any view, you can specify, "i want thisview to be 48 dp by 48 dp." if it turns out that yourcustom view is just always going to be the same size,like skip this entirely,
just define it in yourxml, and you don't have to worry about that. in this particular casebecause the size varies based on the number of labels, ihad to write my own measure. and so a quick way of goinggoing through onmeasure, the message signature thatgets called, you have these width measurespec, andheight measurespec, which was sort of confusing to meat first, but it turns out that these are just packed integers.
so it's a single integerthat, these two parameters basically take the placeof four parameters, which is that a widthmode in size and a height mode in size. so the size is just a dimensionvalue, the mode though is telling you how it wants you to handle that particular size that it passed. and there's three differentmeasurespecs for the mode. one is exactly, whichmeans the parent view group
wants you to be this exact size. the other is at_most, soit take up as much space as possible, and undefinedmeans you get to define whatever ideal width youwould like in the situation. and so your typical onmeasurelooks something like this, where you grab,and this is just for the width, and then youwould copy the same code for the height. you'd grab the mode and thesize, if the measure spec
is exactly, you probablyjust wanna pass back the size that it gave you. you don't wanna screwup the parent view group too much, or else it might get confused. otherwise, calculate whatyour desired width is, and if the width specis at most, then make sure that whatever yourdesire width is not larger than that size. otherwise, if it's undefined, you just get
to pick whatever desired width you want. then, once you've donethis for both the width and the height, you areby contract required to call set measure setdimension, in order to tell the view what you decidedfor the width and height. 'cause there's no returnvalue for onmeasure, you just actually have tocall this measure at the end. so that's measuring how bigthe view is, and the second is ondraw, and this oneis pretty simple, it just
gives you a canvas, and you draw. and so i'm gonna leave thisup to you, because what am i gonna say about canvas? this is not a talkabout how to use canvas. another thing worth considering,is maybe in some cases, you don't actually need acustom view, you could just write your own custom drawable. and the advantage hereis there you could take this custom-written code andapply it to any different view.
so that's good if youwant so me special custom background of sorts. in that case, onmeasurejust becomes something like get intrinsic heightand get intrinsic width on a drawable, and thenondraw becomes draw. but again, i don't wannaspent do much time on this, you can research more aboutit later, i highly recommend cyril motier gave a talkabout android drawables a few years ago, and i highlyrecommend that talk if
you wanna learn more about that later. and i'll be posting theseslides too, if you wanna get the links. alright, styles, let'smove away from views, well, not that far from views. but talk about kind ofanother layer above views, which is styles. so if you are applying xml to a view, this view has no style.
not because it's uncool,but because there is no style tag on it. and then, if you have astyle, all it does is i'm creating some styleresources, which has the same attribute inside of it,and then the view itself then applies that style ontop of whatever, actually, the style's applied firstand then whatever attributes are applied on top of it. but essentially then, inthe same way that includes
or taking layout xml andjust stuffing it into a view group, stylesbasically take a bunch of attributes and stuff it into a view. and so where is this useful? it's very efficient whenyou need to style a bunch of what i call, semanticallyidentical views the same way. and so what i mean bysemantically-identically is that each view does exactly thesame thing in your hierarchy. so a good example of thisis a calculator, because in
a calculator you want allthese buttons, or at least the main number ones to look the same. another way to put it isthat all the style views should change at once. so whenever you wanna change something. so if i wanna change thetext size of one of those buttons, my expectationis that all of them change at once. so that saves me a whole bundle of time.
i see a lot of peoplethough, myself in the past, especially, misusing stylesin very inefficient ways, ways that end up bitingyou in the long-run. and one way is single-usestyles, so that is you have a view that's representinga style, and that style's only used once. i feel like that's justextra work that didn't need to be there. some people really likeseparating all this code
out, but it's so easy to refactorlater and create a style. there's even a refactoringoption in android studio that lets you do this. so, not really necessary. but more importantly, iswhere you have two views that are coincidentallyusing the same attributes. so i've got these two textviews, and i say, "oh look, they're using the same textcolor and text color hint, great, i'll use a style here."
but if you look at the ids,you can tell that these two mean something verydifferent from each other, one's supposed to betitle, and one's the body. and so what happens is, suppose later on i decide, "oh i want the title to be like a different color." well, if i change the colorof the title now, that also incidentally changes the body. and so this style whichwas supposed to be handy
is now just a hindrance,because it's very hard to modify that style without having some unintended consequences later. i liken this to in java,imagine i have two constants, one is like the numberof columns i'm gonna show in some grid. and the other is thenumber of retries i'll do in some http request if it fails. and so i think, "aw, theseare the same value, i'm
gonna optimize this andhave a single constant." and problematic for tworeasons, one is that three is already a constant,but the other is i've lost all semantic meaning. these meant somethingvery different; if i wanna increase the number ofretries for http, suddenly now i've changed how my uilooks as well, incidentally. so that's mistakes peoplecan make with styles. so themes are sort oflike styles on steroids.
styles you can apply to individual views. themes are essentially things that you can apply to multiple views at once. and so that can be aview group, it can be an activity, or it can bethe entire application. it allows you to applydefault styles as well, so if i come up with, iwant all of my buttons to look slightly differentacross the app, without themes i would have to go take thatstyle and actually add it
to all of my xml. whereas with themes i cansay, i would just like to have a default style for allbuttons, and it automatically gets inflated for everything. and then the last lazything that it helps you with, at least in the contextof my talk, it allows you to configure your system-created views. so if you've got popup windowsor toolbars or something that the system creates,and that's one fewer thing
you have to create. but before you could themeon a view level, there was a lot of problems with oh, ihave to create some attributes that affect just this oneweird popup, but then it screws up another part of my app. but it's very useful forconfiguring just things that the system will create. so there's three ways to applyit, you can apply it like i said to the entireapplication, you can apply it to
individual activity, if youdo that, it ends up overriding whatever's in the application. and on top of that, you canapply to an individual view. and in the view case, itends up actually overlaying, so you can just overlaylike a few changes to it, an individual views theme. and the view themeing is very, very handy. i don't know if anyonehere's worked in the days of holo probablyremembers that there was a
holo.light.width actionbar, and that was because there was no way to themejust the action bar part of the screen differently. so you have to say in thetheme, i want to define most of the screen to belight, but i want this one part of it to be dark. whereas nowadays, you cansay, "i would like just a light theme," and thenmanually apply a dark theme to the tool bar itself, so itmakes things so much easier.
so in terms of theming, ihighly-recommend people look into appcompat, which isone of the support libraries that google puts out. if you're not already usingit, amongst other things it makes theming a lot easier. for one thing, it gives youmaterial on all devices, like that's the latestdesign language from google, and without this, there'sa lot of subtle differences between holo and material,in terms of spacing, and
also in terms of just the visual metaphors that they're using. and so it's so much easierto start from one single baseline, and then theme from there. another thing is, it givesyou all these baseline themes and styles. so you might wanna changethe default look of all your buttons, but you don'twanna have to actually go and define a style,which defines every single
attribute that a button has to have. you just wanna take the mainone and tweak it a little bit, like add a little paddingto all of your buttons. and so appcompat makesit easy then, to take the appcompat button styleand extend from that, and then modify it. without that, it becomessort of a nightmare, especially between holo and material. and the third reallyimportant thing it enables
is that it allows you to doview theming pre-lollipop, in xml, and that was oneof my favorite things, because lollipop had thisview theming which seemed really cool, but i waslike, "oh, but you can't get it backported." they actually did manageto backport that all the way back to i think,some api that you shouldn't even be using anymore. i think 11.
sorry people who arestill having to support apps on 11. so a few examples of thingsyou can do with themes, the one that gets toutedeverywhere is the color theming, so in this case,instead of having to use individual drawables foreverything, i can just set up colors, and most of thethings in android will just get colored automatically. so bam, it's like a broadbrushstroke you can make.
these are some examples ofapplying default styles. so, just in case you'venever seen this before, so for example the top line,defines the button style for the entire application,so that gets applied to every button. the spinner item style ishandy because what if i just wanna use the built-inspinner item layout row that android provides,but i still wanna style it a little bit,i can use that here.
text appearance is nicebecause then the text appearance can apply totext views, and then you can still apply anotherstyle on top of that. another useful thing youcan do with themes is that you can set upattributes which are then referenced in your xml. so in these case selectableitem background, which is like one of my favoriteattributes, if you refer to it with that ?attribute/ insteadof the @drawable that you
normally use, then itderives that value from the theme instead of going to it directly. so why is this useful,if you happen to have an app that supportsmultiple themes, it makes it very easy then to swapbetween those values, but more importantly, your systemmight have multiple ideas of what a selectableitem backgrounds it's, because pre-lollipop, herewasn't any ripple drawables. it was just usually justa flat color that you
changed to whenever youclick on something, whereas post-lollipop, you wannahave these ripples because it looks really cool. and so if you use aselectable item background, then the theme canautomatically figure out which one it wants to take. alright, i'm gonna do aquick water break before i move on to the next section. sorry.
alright, resources, so,resources are you know, all the things that gointo your app that aren't just pure java code. and before i can talk aboutresources, i wanna talk about device configurations. so if we look at thisscreenshot there's like a whole bunch of things that onecan derive about it in terms of its configuration. so for example, i can sayit's in portrait orientation,
it's got a height of 731density in a pint of pixels, it's got a width of 411of them, it's a nexus 6p, so it's got a density ofxxxhdpi, it happens to be in english rightnow, the english locale, so it's showing english u.s.and it's version 24 'cause it's running the latest n builds. so these are all things thatthe android system knows about the device, and youcan query this all manually on your own if you want,but actually with resources
you can just have it selectthings automatically. and some of these devicethings will change throughout execution, some of them won't. so portrait vs. landscape,unless you're locking your orientation, thatcan change very rapidly. you change the locale,people probably won't change that often, but they can changeit while your app's running. and then some things like thedensity and what operating system version probablyaren't going to be changing
while you're running your app. so what sort of things doyou wanna vary on this? well landscape versusportrait, i think is a classic example, because it usuallypresents a different mode of operation. the built-in calculatorapp, when it's in portrait, only shows four rows, butwhen it's got more space to stretch out, it canpossibly show some of the more cool functions, just by default.
locale is a very easy one,you wanna have your app translated in a differentlanguages, you just have have it select differenttext strings based on the locale, so on the left it'sin english, on the right it's in japanese. you can have things breakon the width of the screen, so on the phone the cardwhen it's opened is small enough that it just decidesto take up the full width, whereas at some point, ifthe device gets large enough,
it just looks kind ofridiculous having it be full width, and so we starthaving a break point at some moment with width. and another example of thatwould be like our search results, we have the staggeredgrid view, and again, on the wide tablet itwouldn't make sense to have a single column, it makessense to fill it up as much as possible, and so we canvary the number of columns based on that.
and then also on the mobilephone you can see the top result is some small boarddisplay, because it's a small device, whereas on thelarger tablet, we can show the nice big rectangle, whichwould look nicer if that actually had a background, but whatever. so you could do this allin java code like i said earlier, but it's a loteasier if you just leverage the resource qualifier system. and what this system doesis you define alternative
resources for differentdevice configuration and then at run time android willautomatically pick the correct resource based onthe device configuration. so it's go through anquery everything and figure out which of the resourcesyou defined makes most sense in this situation. and so you define this bythe names of the folders, so in your resources directoryif you have something that's just the defaultvalues, that means it has no
resource qualifiers attachedto it, it's the default fallback in all cases. whereas if you do a singledash and then a resource qualifier, so this one hasone resource qualifier, it's xxxhdpi, and you canhave multiple qualifiers if you want. you can actually applyas many qualifiers as you want to a single value,although usually it isn't handy if you do it tomany different values.
and one other thing worthnoting is that if you do have multiple qualifiers, theyhave to go in a particular order, so look up thedocumentation, the documentation has this huge table of allthe different qualifiers that you can use, and you haveto put them in the order of that table for androidto parse it correctly. so that same documentation page also lists out the algorithm, butpretty much it's just like a process of elimination.
it tries to find the mostspecific resource, given the current configuration. so imagine i start with somevalue, and i've got something in values with smallestwidth 600dp, smallest width means that regardless oforientation, what is the smallest width that you can possiblyhave for the device, which is useful for figuring outkind of the device class, like tablet versus phone. and it also has to be in portrait.
so then it would selectfrom this if those are true, but if it turns out oneor the other isn't true, then it'll start lookingto see other things it can eliminate. so then it'll look maybefor just the single sw 600 dp, oh, it turns outthe phone doesn't qualify for that, so then it'll seeis the phone in portrait, and if it doesn't qualifyfor that, then it'll fall back to the base values here.
so that's why it's handto have a default value for everything, the onlything you don't really need a default value for isdrawables because the way that android works it'llautomatically scale if you don't have something in the right directory. so if you only have xxxhdpiassets and your device happens to be mpi, it'lljust scale everything down, which isn't greatperformance-wise, 'cause having to do all that extra work,but at least you don't have
to worry about that whenyou're developing quickly. so in terms of using resourcequalifiers in the correct way, what i think is important is to think of these resources as code. in particular, to think ofeach resource that you're inserting somewhere as aparameter to some method function, a method or function,and that the parameter's determined based on thedevice configuration. so for example, if you'rethinking about this in terms
of code, the code on theleft is insane and dumb because i'd have to writea new square function per number that i want to square,whereas the one on the right has this parameter. so you wanna think of itmore in terms of the things on the right. so one simple example, onthat i like to use a lot, is actually letting theresource qualifier system determine some boolean logic for me.
so this is a simple onewhere i basically just wanna know whether it's in portrait or not. yes, you could query thisfrom resources fairly easily, but this is just an example. so i could say, "by default,is portrait is false, and then in particular,when it is in portrait, then it's true." and then i can get this boolean value out. but this is really handyif you have multiple
different configurationsand multiple ways that that boolean could run, itcould do all that calculation for you, you don't have to think about it. a more classic example isusing it for different layouts. so i could say i'm gonnacall set content view, and i have these three differentversions of layout, one that's the default, one that showsup in landscape orientation, and one that shows upin portrait orientation. and i made this slide farbefore i realized it's very
improbably to actually endup ever without it being in landscape or portrait,you'd have to have a square screen for that. but basically, it's selectthe right one of these, but would be more clever,'cause this you'll probably end up with some duplicated code. 'cause chances are,there's not that much that changes between portraitand landscape, so it's then if you can use that codereuse, the include, and then
it can switch on just thatpart of the code that changes. so i've got my linearlayout,and inside of it somewhere there's an include, andthat's the only part that changes based on orientation. so now i can have a singleactivity main, and i can have a layout that's thedefault one, and then the layout that just modifies in the portrait. along the same lines, let'slook inside that include, suppose both those includeshave text view which are
supposed to be pretty muchthe same thing, but all that they really modify onis what the text size is. but this again, thisseems kind of like a waste to have two differentlayouts here, if all i really wanna modify is the text size. so here what i can do is i canthen reference a dimension, and then that dimension canbe then determined based on the qualifiers as well. and then to take this even astep further, let's suppose
we have style somewhere inthe application, that's the same sort of thing, allthat modified is the text size, so i can again,have this be a dimension, but now this style canbe applied all over the the application insteadof applying that dimension trick to just one particular view. so in this example, i havean activity main on top, and then by default to goto to one include, but if it happens to be in portrait,it'll go to a different include.
both of those include atext view, which is supposed to be ostensibly the samebetween both, so they use the same style. and then that style, basedon the current configuration determines what the text size is. so you can really gopretty deep with this and write very littleduplicated code between all of your layouts, if all thatyou're doing is changing things based on device configuration.
and as an aside, this iswhy generally speaking, you shouldn't overrideconfig changes on android. that's a pretty common beginner way to get around the problem of, oh,i rotate my phone and then my activity got destroyedand i didn't want that to happen, 'cause wheredid my all my data go? and then someone says,"hey, if you just override config changes, everythingworks out, and all of your data stays around."
there's two problems withthat, one is that it doesn't necessarily help you becauseyou probably only override config changes for orientationchanges, but there's a lot of other ways thatthe configuration could change on the fly. but for two, it means thatyou bypass this system entirely, cause you'rebasically telling the android system, "i've got this,don't worry about it." this whole resourcequalifier system is a major
part of the reason whywhen you rotate your phone, the activity getsdestroyed and recreated again, because it wants you tore-inflate everything, because when you re inflate everythingsomething might have changed based on selectinga different layout. alright, drawables, sothis is, let's see how much time i have, good. alright, so drawables isthe last section i wanna talk about, and i wannaoutline sort of a nightmare
scenario that you may ormay not have gone through. i certainly gone through this, many times. so imagine i'm interactingwith design, and they send me a mock-up of a new screen. and in particular this isthe login screen, and they wanted to add this loginwith ssl thing at the bottom. so then i look at this,and i start working on it, but then i tell design, "ineed this asset, 'cause i'm not good at design oranything, i need you to give
this to me." so design says, "okay, sure, no problem." so they send you over azip file, you unzip it, and you get this one filethat is who knows how big this is supposed to be. so you tell design. "okay,this isn't enough, i need more than this, i need one inall the different densities." and design says, "oh sure,"they go do some research on how that works, andthen they send you back a
file like this, and azip that contains this. so now you've got allthe assets that you need, but then you have to gothrough an rename everything and put it in the rightfolders, and then import into your project, it'skind of just a pain. and that's a real painto do with every asset, and then the kicker ontop of all of this is that at the very end, designsays, "actually, i wanna tweak the color, and here'sa new set of assets."
and so now you have to gothrough this whole process again, and it's agigantic pain in the ass. so my recommendation here,i've been working with the design team at trello,and we figured out a whole bunch of ways to reduceall of this pain and all this friction. and it's just made thingsso much simpler, and it's basically to think of assetsas code, as much as possible. don't think of them asbitmaps that you get from
design as much as you can,think of it as things that you can execute in your application. because then it's so muchfaster to tweak and change things on the fly. so the first example of thisis drawable xml, which has been in android since the very beginning. and drawable xml areresources that you can define, you can do things like drawsimple shapes, you can do things like set up stateselectors, so that's where
if you press a button andit looks slightly different, that's a state selector. you can use it as a layerlist, and this is really handy because if you havetwo drawables that you actually wanna layer on topof each other with multiple states in between both ofthem, you might have thought, "okay, now i need to designto composite all of these images for me." actually, you can just setup a layer list, and then
change the two layersindependently, you get that nice composition going on. so a detailed example forthis are the login buttons that i worked on once. and so these loginbuttons are entirely done through drawable xml. so the first step to makingthese login buttons work is that i need to create that button outline. and the button outlineitself is just its own file.
so we're not worrying aboutthe click state right now. and it uses a shape drawable,the first important part is you can tell it what typeof shape you want, you can also make ovals and stuff like that. but you're limited to verysimple shapes with drawable xml. i wanna say that it's mostlyfilled with transparent space, in fact, that shouldbe the default, but on some older versions of androidit was not defaulting to transparent for solid, idon't remember exactly why.
then i do want that whiteoutline though, so i give it a stroke, which thendetermines that outline, and i would like to havea small radius on it so it gets that nice little pretty button look. so that's just creating theoutline, the blue actually comes from the backgroundof the entire screen, i just put it there 'cause otherwiseit would be really hard to see with my whitebackground on the slides. so then we need to addsome behavior to it.
when i click it, i wannaactually be able to tell that i clicked it, and sowe need to add a selector to it, which you can seein this beautiful little two frame gif. and so the way that i'm doingthis is actually layering a selector on top of thatoutline i just talked about. so i'm using a layer list,and that layer list allows me to take two drawables andput one on top of the other. and i'm saying the top layeris that outline that i just
showed you, that's theprevious code that i showed you, is what's going on top., so that's always going to be drawn. and then the other layer isa selector, and the selector just has two states in it,and one of those states is when it's pressed,then i want you to draw this other shape. so again, i'm using anothershape drawable in order to determine what shouldbe drawn inside of it,
and in this case it's alittle simpler, 'cause i can just say, "i want you tohave a solid color, but then again, also have thecorner so it doesn't end up bleeding out of the corners." and then when it's not pressedand in the default state, then it'll just be transparent. so that's great an all, butthen in version 21 of android they added these nice rippledrawables which look really pretty and doing thatrequires a while different
set of code. and so for that, you endup using something that's a ripple xml, somethingwe added in version 21. and that inside there iswhere you say what the color of the ripple should be. and then after that, i add,okay, i still have the same button outline as what'sactually being drawn in that ripple, but then the lastpart of this is that i define a mask.
and that mask basicallysays, "this is the outline of where the ripple should appear." and so then the actualsolid color inside of it doesn't really matter, it'sjust the fact that this drawable will draw to thisparticular area that matters. and so i was able to getaway with all of this and have a different version fordifferent versions of android, by using the resourcequalifier system, so at the bottom there's this outlinethat i'm always going
to be using, but then thedefault button uses the state selector, which will alwayswork all the way back to version one of android, i think. and then drawable v.21for that ripple drawable, i can use there. so drawable xml, a fairly goodway to skip a lot of work. and then i just had to askdesign for the colors, i didn't have to ask them foranything else in particular. vector drawables, so likei said, the shape drawables
lets you draw very simpleshapes, nothing complicated. vector drawables letsyou do any sort of vector drawing you want, or mostvector drawing that you want. and so it allows you to dovery complex shapes, and the advantage here tousing a vector is that you don't have to then worryabout density of the screen all that much. 'cause before i was havingto get these pngs from design that was in allthe different densities,
here they can just giveyou a single vector, and then it's automaticallydrawn at whatever's the best resolution for that screen. so that's a hugetime-saver, but there is one problem with the way that android implemented vector drawable. oh, so another point isthat vector drawables were added recently inandroid, but there was a back compatible libraryin the support libraries
for using vectors allthe way back to i think, 14 or something like that. but there is a big problemwith the way that android did it, which is that theycame up with their own vector drawable formatthat is not actually svg. and if your designers areanything like my designers, they know how to speak svgreally well, all of their tool know how to output insvg, and none of them know how to output as vector drawables.
so you need some way toconvert these svgs that your designers are giving you intovector drawables in the app. so there's sort of two waysof doing that, yeah, sad design, there's two ways of doing this. and one is in android studioyou can say, "i want a new vector asset," and that'llbring up this nice little wizard, and then you canpass in the svg and it'll convert that into a vectordrawable as best it can. there are some svgs thatit doesn't work very well
with and won't convert. so that's good, but i stillam even lazier than this, because i don't wanna haveto go through a wizard every time i import a new asset. so instead, we wrote hisbefore all the vector drawable back compat stuff happened,but we're still using it, which is this android plugin that we wrote called victor. and what victor does, is youdefine any number of source
sets, anywhere that you haveyour svgs, and it'll just slurp all those up, andthen output something that the system can render. and for awhile it just outputpngs but then eventually we were able to get toactually grab the code that is in this new vectorasset stuff and then use that to convert it straightinto vector drawables. so that's great becauseactually with trello, our designers have theirown git repository, which is
where they put all of theircompiled svgs, and then we can just have that as agit submodule, and import it, and then we just haveto update a commit pointer to get new assets fromdesign, that's great. and then so the last thingi'd like to say about drawables that has reallysaved a lot of time recently, is that differencebetween skeuomorphic and flat design. so skeumorphic designis where you have things
that look exactly like whatthey're supposed to be, and so on the left is andiegraph, which is an app that my friend wrote,which makes your phone act exactly like any ti-83, ti-84, whatever, and look exactly like it. so it looks very realistic,that's very skeumorphic, whereas on the right youhave the normal calculator, which is flat, and everybutton is just this flat color. and what's really nicehere is that as nice as the
thing on the left looks, onthe right all the icons and all the text is just a flat color. and what that means isthat it's very easy to tint those colors and change them on the fly. with the buttons on theleft, it would be very hard to tint them in any waythat would be reasonable. so actually, in the trelloapp, all of our assets are flat black colors. so they're black on alpha,and then in code, we take
any of those, and tint itwhatever color we want. and so that's super-handyfrom the perspective of design, because they don'thave to create multiple assets for whatever color they want. every time they wanna changethe colors, we can just say, "oh, that's easy, let'sgo change it in code," and then we're done. so in terms of tintingimages, there's sort of a few ways to do it, one is todo it via xml, but besides
the fact that image viewhas had this tint attribute forever, which doesn'tquite work all that well, it's not backwards compatible. it got added into recentversions of android to be able to tint drawables inxml, but they haven't figured out any way to actuallybackport that functionality. so i ended up doingactually most of the tinting in code, it's very simplewith image view and drawables, you can call set colorfilter,and then you just pass
in the color. and then it turns out thatfor a black icon on alpha, you wanna use the porter/duffmode of source in. that's actually why thexml imageview of the tint attribute there, i don'tlike it very much, 'cause it uses a porter/duff modethat isn't compatible. i think you have to createwhite icons on alpha, which we're not doing at the moment. now if you want a reallycomprehensive solution,
this exists in the supportlibraries is drawable compat, and with that youactually wrap the drawable, and then you can call settint, or set tint list on that wrapped drawable. and main advantage thathas over just calling color filter directly is thatit can handle tint lists, so you can have multipledifferent selected states for that wrapped drawablein color, and you can tint all of it equally.
but since we're notactually using that in the app, we don't end up doingthat very often, and so set color filter's just afaster, easier way of doing it. anyways, so that was all that i've got. this was a slide i wastold to put up as well, to let us know what youthink, click the happy face if you liked it or the sadface if didn't like it. and thanks very much forcoming to listen to the talk, the middle link is to myblog, where i've written
more about some of thesethings and then some parts of this talk weretaken from other talks that were more detailed,in particularly the styles and themes, i went intomuch more detail on that. so you can look at my oldspeaker deck to find those talks if you're moreinterested in learning some of the more nitty-gritty details there. and thank you very much. (audience applause)
were there any questions? - yes, actually therewas one of them, and the question was, whetherperformance was lost in virtual machines and the. my take on it is that,well, the question might mean that if you use like anemulator, and you're doing this, you'll have a slidewith the graphics performance in different layouts, willit affect emulators, do you know that, if?
- so yeah, so let's see here. - i guess that's what-- - i think you're talking about this one-- - [interviewer] (mumbles) yeah. could you actually findout that your layout are kind of-- - through an emulator? no, i'd use a real device for this. - [interviewer] yeah,you'd use a real device.
- yeah so i wouldn't, forthings like profiling, the emulator can reallymake things awkward because it could be the case thatyou have this gpu, if you're working on a windows desktopor something, you're gonna have a gpu that's bigger than your phone, running the rendering. and that's gonna throw thingsoff a little bit, obviously. or it could be the case thatwhatever, i think it used to be that it was translatingfrom arm into x86,
and then that would be reallyslow, and so all the cpu operations would be really slow. basically yeah, i would usean actual device for all sort of profiling purposes. - okay, and do you, you touched upon this new constraintlayout,is that something you played with or? - yeah, i played with constraintlayout. - you believe it's the savior, or?
- i hope so, 'cause itdoes a lot of things that, it's sort of like thiscomposite of relativelayout and linearlayout right now,that allows you to create very complex layouts withouthaving too much nesting. and so the hope is thatyou'll be able to create these complex layouts withoutmuch nesting, and that through the constraintsystem, it can better figure out what are the moreperforming way to lay things out quickly.
so i'm hoping that itsaves us from having to use relativelayout more often. (laughs) - [interviewer] yeah, i thinkyou have more questions. please come down and talkwith them afterwards. - yeah. - [interviewer] but thank youvery much, dan, and remember to rate the session and ican see some of the speakers
here from the android track,so thank you very much, it has been a pleasure.
and yeah, please give him a hand. - thank you.