I don't know how many hours I've spent struggling with Android's theme engine, trying to figure out — mostly  by trial and error — how styles are applied and how to properly define them (let's be honest: the documentation on styles in Android is a bit lacking). I thought it may be worth sharing what I've found out so far, in order to save my fellow Android developers  from baldness due to ripped out hair (I sure lost some). This is a work in progress (so is Android), and some information may be inaccurate. If you find anything that you think is wrong or unclear, please let me know by dropping a line in the comments section.  On another note, I assume that you have read the reference  documentation on Android styles, if not, you should do that now.
  
 What are Android styles?
  A style in Android is a collection of attribute/value pairs applied to a view, an Activity or the entire  application (which means, all Activities in your application). Styles for Activities are called themes, but do not get confused: they are syntactically equivalent to styles (because they are styles),  they merely have a different scope. At this point I want to clarify something upfront: Themes or styles in Android have nothing to  do with user styles known from applications such as, say, Firefox. Android users can not change the looks of Android applications by downloading themes from the Market or creating their own (yet). Android themes are of interest for developers only, think of them as syntactic sugar, a way  of making your application's view code more DRY
 .  Let's  look into a simple theme definition (stored in res/values/styles.xml):
   
   
   
   
   
  First,  we declare a new theme called MyTheme, which inherits from  another theme called Theme.Light in the android namespace (specified by the 'parent' attribute). This means that all styles we do not explicitly specify in our custom theme will be merged down from the definition of android:Theme.Light (the curious among you may want to download the Android source code and go to frameworks/base/core/res/res/values to see how it is defined; all stock styles  are defined in themes.xml and styles.xml in that folder).
 In  our theme definition, we also set some custom styles using the 'item' element. We set the windowNoTitle attribute to true, so all activities that use our theme won't have a title bar. We also set the window background color to a custom color called 'translucent_blue'; this is a resource reference  (indicated by the @ symbol) to a color definition in values/colors.xml. We could also have passed a reference to a drawable here, or have provided a hex color value directly. Finally, we set the default style for ListView widgets to a custom style called  MyListView. Its style definition follows the exact same structure as the  MyTheme definition, just that this time it is not a theme, but simply a style that can be applied to ListView objects. It inherits from the default styles for ListView but replaces the default selector image with a custom drawable.
 There  are two important things to understand here. First, those two style definitions are completely independent of each other (well, apart from the fact that we reference MyListView in MyTheme of course). This means, that if I remove the reference to MyListView from MyTheme, I can still use that style by applying it manually to a ListView declaration in a layout file. Think of styles simply as a bunch of attributes and values you would have otherwise typed directly into your view definition, so instead of writing
  we  write
  or  better yet, we let this style be applied automatically to all  ListView widgets by setting it in a theme definition (as seen above). (Note the missing 'android:' namespace reference here; this is intentional, the 'style' attribute is not defined in the 'android' namespace. You will get an error if you try to set  a style using 'android:style', there is no such attribute.)
 That  way we never have to touch the ListView definition anymore; we can do all its styling from a single point, the style sheet. This helps in leaving the code for defining structure in  your layouts, while leaving the code for definingappearance in your  style sheets — a good example for separation of concerns.  More importantly, your style definitions can be reused, which is particularly useful if styles are shared between several views.
 The  other important thing to understand is that styles do not have any type semantics. When we create a style called MyListView which inherits from Widget.ListView, then the intuition is that we are creating a style that is only supposed to apply to ListView objects. That's not entirely correct though. There is no mechanism that will check whether we indeed apply that style to a ListView or even prevent us from applying it to an entirely different view type. It just so happens that Widget.ListView defines some attributes that only make sense when being applied to a ListView (such as listDivider), this doesn't stop us, however, from creating a style that totally makes sense for any widget type (maybe because it only uses attributes defined in the View class, the parent  class of all views). The bottom line is that you have to figure out yourself whether a style you define makes sense when you apply it to a view. Android will not do any sanity checks for you. In the worst case, the targeted view will expose odd behavior when  being rendered, but more probably nothing will happen at all.
  To  get going with styles, it's of course important to know two things:
  1.      what's there to be styled, and
  2.      what styles are already there to inherit from
 The  easy answer is: Anything in android.R.styleable can  be used inside a style body as a subject for styling (using the item tag), while anything in android.R.style can  be used as parent styles to inherit from. So, to stick with the  ListView example style, the android:listSelector style item can be found in android.R.styleable, while android:style/Widget.ListView is defined in android.R.style. Those two files are therefore what you want to turn your attention to first when defining custom styles. You should generally always inherit all default style items first, and then overwrite them one by one with  your custom items.
 That's  basically already it, a simple yet powerful style framework if used correctly!
   Did  you find yourself defining text appearance like font size or text color over and over again in your layouts? Don't do that, use text  appearances instead. Text appearances are styles, too, and Android already defines some for you which you can override (they are, of course, defined in R.style). This helps tremendously in keeping your view code DRY, and encourages you to get some structure into your different font styles used throughout your app by grouping them into styles you can reference and reuse. If, for  example, you want to change the default text appearance in your app, simply define a custom text appearance in your stylesheet and set it as the default in your theme:
   
   
   
   
   
  Make  yourself familiar with all the text appearances Android already defines, and customize them for your application as you see fit.
  Avoid  setting color values directly in layouts or styles. Define them in a color resource file instead, and only use references to those color values from your layouts and styles. This helps in isolating them from the rest of your view code and makes your styles  less brittle if you should decide to change a color afterwards. For simple, non-stateful colors, you can simply create a colors.xml file in res/values:
   
   
  Often,  however, colors can be more complex. If, for instance, you use a custom list selector image, it may happen that list text is readable when not selected, but becomes difficult or impossible to read when the custom selector is drawn (e.g. because the coloring  is too similar). In that case, you need a ColorStateList,  which you can use to automatically change colors for the view it's applied to, based on that view's state. Start by creating a new file, e.g. 'stateful_text_color.xml' in your res/colors directory. The resource root is 'selector', which is what you always use when creating resources that change with a view's state:
   
   
   
  You  get the idea. You can set this stateful color resource like any other color, it's simply defined in a different way.
 Also  keep in mind that there are already color definitions shipped with Android. The most useful of them is probably android:color/transparent, which corresponds to the color #00000000. The first 8 bit, i.e. the first two hex digits, represent the alpha channel which is used to define opacity. A value of zero means zero opacity, or 100% transparency; the remaining color bits are therefore of no relevance, because they will be invisible. You can then turn the background  of your views transparent by doing something like:
   
  That's  it for now. If I find out more about styles in Android, I'll update this post accordingly. Feel free to contribute in the comments section, too.
  
    
0 件のコメント:
コメントを投稿