Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Android Themes & Styles demystified (Google IO 16)

Android Themes & Styles demystified (Google IO 16)

Themes and styles are the bedrock of styling your Android UI, but do you know how they work? This talk will dive deeper into everything you have ever wanted to know about how styles and themes work together, what attributes really are, and how you can use them to make your styles more manageable.

Chris Banes

May 18, 2016
Tweet

More Decks by Chris Banes

Other Decks in Technology

Transcript

  1. In what Android version did Theme.Holo appear in? 1. Android

    Eclair (2.1) 2. Android Honeycomb (3.0) 3. Android Ice Cream Sandwich (4.0) #holoyolo
  2. In what Android version did Theme.Holo.DarkActionBar appear? 1. Android Honeycomb

    (3.0) 2. Android Honeycomb MR2 (3.2) 3. Android Ice Cream Sandwich (4.0)
  3. How did selectableItemBackground change in KitKat? 1. Changed to a

    ripple 2. Changed to monochrome 3. Changed shape
  4. From what version can you use android:foreground on a View?

    1. Android 1.0 2. Android Ice Cream Sandwich (4.0) 3. Android Marshmallow (6.0)
  5. Themes and Styles They’re technically the same thing Both declared

    using the <style> tag The only difference between them is how they’re used Themes == Styles used in a special way
  6. Themes and Styles At their simplest, are just key-value stores

    <style name="MyStyle"> <item name="android:background"> @color/blue </item> </style> Key Value
  7. Attributes namespaces All attributes provided by the framework are in

    the android schema <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:background=”...”>
  8. Custom attributes You can also create attributes You’re probably using

    libraries which already do so Important to know that non-Android attributes are global within your app
  9. Custom attributes Global namespace All custom attributes are in your

    app’s schema <ImageView xmlns:app="http://schemas.android.com/apk/res app:customAttr=”...”> /<your_pkg_name>" -auto"
  10. Default widget styles android:editTextStyle Color values android:textColorPrimary Text Appearance styles

    android:textAppearanceSmall Window configuration values android:windowActionBar Drawables android:selectableItemBackground android:listChoiceIndicatorSingle Themeception android:actionBarTheme android:dialogTheme
  11. Styles A set of values which are used to style

    a View res/layout/main_activity.xml <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="..." android:background="@drawble/my_drawable" />
  12. Styles A set of values which are used to style

    a View res/values/styles.xml <style name="MyStyle"> <item name="android:background"> @drawble/my_drawable </item> </style>
  13. <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="..." /> Styles A set of values

    which are used to style a View res/layout/main_activity.xml style="@style/MyStyle"
  14. Inheritance Themes can inherit from each other Handy for creating

    derivative styles Styles overlay each other
  15. Styles Can reference values from the theme res/values/styles.xml <style name="MyStyle">

    <item name="android:background"> </item> </style> @drawble/my_drawable
  16. Styles Can reference values from the theme res/values/styles.xml <style name="MyStyle">

    <item name="android:background"> </item> </style> ?android:attr/selectableItemBackground
  17. ?android:attr/ Styles Can reference values from the theme Denotes that

    we’re doing a theme lookup selectableItemBackground
  18. ?android:attr/ Styles Can reference values from the theme We’re looking

    up something within the android namespace selectableItemBackground
  19. frameworks/.../res/values/themes_material.xml <!-- Material theme (dark version). --> <style name="Theme.Material"> <item

    name="colorForeground">@color/foreground_material_dark</item> ... <item name="buttonStyle">@style/Widget.Material.Button</item> <item name="editTextStyle">@style/Widget.Material.EditText</item> <item name="seekBarStyle">@style/Widget.Material.SeekBar</item> ... <item name="listPreferredItemHeight">64dp</item> <item name="listPreferredItemHeightSmall">48dp</item> <item name="listPreferredItemHeightLarge">80dp</item> ... </style>
  20. Overlay themes Applied to a section of view hierarchy ThemeOverlay.Material.Light

    ThemeOverlay.Material.Dark ThemeOverlay.Material.Dialog (API 23+)
  21. frameworks/.../res/values/themes_material.xml <!-- Theme overlay that replaces colors with their light

    versions but Preserves the value of colorAccent, colorPrimary and its variants. --> <style name="ThemeOverlay.Material.Light"> <item name="colorForeground">@color/foreground_material_light</item> <item name="colorForegroundInverse">@color/foreground_material_dark</item> ... <item name="textColorPrimary">@color/primary_text_material_light</item> <item name="textColorPrimaryInverse">@color/primary_text_material_dark</item> ... <item name="colorControlNormal">?attr/textColorSecondary</item> <item name="colorControlHighlight">@color/ripple_material_light</item> ... </style>
  22. frameworks/.../res/values/styles_material.xml <!-- Material text appearances. --> <style name="TextAppearance.Material"> <item name="textColor">?attr/textColorPrimary</item>

    <item name="textColorHint">?attr/textColorHint</item> ... </style> <style name="TextAppearance.Material.Button"> <item name="textSize">@dimen/text_size_button_material</item> <item name="fontFamily">@string/font_family_button_material</item> <item name="textAllCaps">true</item> ... </style>
  23. Widget styles • Prefixed with Widget • Implement Material spec

    • Provide default attributes See ApiDemos for examples
  24. frameworks/.../res/values/styles_material.xml <!-- User-adjustable seek bar. --> <style name="Widget.Material.SeekBar"> <item name="progressDrawable">@drawable/seekbar_track_material</item>

    <item name="indeterminateDrawable">@drawable/seekbar_track_material</item> <item name="thumb">@drawable/seekbar_thumb_material_anim</item> <item name="splitTrack">true</item> ... </style> <!-- A seek bar with tick marks at each progress value. --> <style name="Widget.Material.SeekBar.Discrete"> <item name="tickMark">@drawable/seekbar_tick_mark_material</item> </style>
  25. Theme colors • Defined by the theme • Allow high-level

    styling • Ensure consistency For example, ?android:attr/colorAccent
  26. frameworks/.../res/colors/btn_colored_bg_material.xml <!-- The background color of a bordered colored button.

    --> <selector> <item android:state_enabled="false" android:alpha="?android:attr/disabledAlpha" android:color="?android:attr/colorButtonNormal" /> <item android:color="?android:attr/colorAccent" /> </selector>
  27. frameworks/.../res/colors/switch_track_material.xml <!-- The foreground tint of a switch track. -->

    <selector ...> <item android:state_enabled="false" android:color="?attr/colorForeground" android:alpha="?attr/disabledAlpha" /> <item android:state_checked="true" android:color="?attr/colorControlActivated" /> <item android:color="?attr/colorForeground" /> </selector>
  28. Drawables Support ColorStateList and theme attributes since API 21 <ripple

    android:color="?android:attr/colorControlHighlight"/> <shape android:shape="..."> <solid android:color="@color/selectorWithFocusedState"/> </shape>
  29. ColorStateLists Support theme attributes since API 22 <selector> <item android:state_enabled="false"

    android:color="?attr/colorControlActivated" android:alpha="?android:attr/disabledAlpha"/> <item android:color="?attr/colorControlActivated"/> </selector>
  30. -night qualifier Resource qualifier like -land or -sw720dp Set when

    device is in Night mode Simplifies swapping light & dark resources
  31. Overlay themes Applied to a section of view hierarchy ThemeOverlay.Material.Light

    ThemeOverlay.Material.Dark ThemeOverlay.Material.Dialog (API 23+) FLASHBACK TO EARLIER...
  32. android:theme Allows override theming on a View Theme is applied

    to that view and any children* Implemented using ContextThemeWrapper * When inflated as XML child or against View.getContext()
  33. frameworks/.../android/view/LayoutInflater.java // Apply a theme wrapper, if specified. TypedArray t

    = context.obtainStyledAttributes( attrs, new int[] { R.attr.theme }); int themeResId = ta.getResourceId(0, 0); if (themeResId != 0) { context = new ContextThemeWrapper( context, themeResId); } t.recycle();
  34. frameworks/.../res/layout/screen_action_bar.xml <!-- Layout for a screen with the Action Bar

    enabled. --> <com.android.internal.widget.ActionBarOverlayLayout android:id="@+id/decor_content_parent" ... android:theme="?attr/actionBarTheme"> <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container" android:layout_width="match_parent" ...
  35. frameworks/.../res/values/themes_material.xml <!-- Light theme with a dark action bar. -->

    <style name="Theme.Material.Light.DarkActionBar"> <item name="actionBarTheme"> @style/ThemeOverlay.Material.Dark.ActionBar </item> <item name="popupTheme"> @style/ThemeOverlay.Material.Light </item> ... </style>
  36. Incorrect style parent <style name="MyTheme" parent="@andrid:style/Theme.Material"> <!-- Rest of theme

    --> <item name="android:editTextStyle"> @style/MyEditTextStyle </item> </style>
  37. defStyleAttr vs defStyleRes View 4-arg constuctor View(Context context, AttributeSet attrs,

    int defStyleAttr, int defStyleRes) obtainStyledAttributes() obtainStyledAttributes (AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
  38. defStyleAttr defStyleRes The attr in your theme which points to

    the default style The resource ID of the default style R.attr.editTextStyle R.style.Widget_Material_EditText
  39. Search order when evaluating attribute value: 1. Value in the

    AttributeSet 2. Value in the explicit style 3. Default style specified in defStyleRes 4. Default style specified in defStyleAttr 5. Base value in this theme Context#obtainStyledAttributes() // values set in layout
  40. Search order when evaluating attribute value: 1. Value in the

    AttributeSet 2. Value in the explicit style 3. Default style specified in defStyleRes 4. Default style specified in defStyleAttr 5. Base value in this theme Context#obtainStyledAttributes() // using style attribute
  41. Search order when evaluating attribute value: 1. Value in the

    AttributeSet 2. Value in the explicit style 3. Default style specified in defStyleRes 4. Default style specified in defStyleAttr 5. Base value in this theme Context#obtainStyledAttributes()
  42. Search order when evaluating attribute value: 1. Value in the

    AttributeSet 2. Value in the explicit style 3. Default style specified in defStyleRes 4. Default style specified in defStyleAttr 5. Base value in this theme Context#obtainStyledAttributes()
  43. Search order when evaluating attribute value: 1. Value in the

    AttributeSet 2. Value in the explicit style 3. Default style specified in defStyleRes 4. Default style specified in defStyleAttr 5. Base value in this theme Context#obtainStyledAttributes() // don’t rely on this
  44. View attributes in themes <style name="MyTheme" parent="@style/Theme.AppCompat"> <!-- Yadda -->

    <item name="android:background">...</item> </style> #obtainStyledAttributes() 5. Base value in this theme
  45. View attributes in themes Any view which doesn’t have a

    background set, will use the theme’s value