Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Using styles and themes without going crazy

Using styles and themes without going crazy

Presented at Droidcon NYC 2015.

D225ebf0faa666ac7655cc7e4689283c?s=128

Daniel Lew
PRO

August 27, 2015
Tweet

Transcript

  1. Using styles and themes without going crazy Dan Lew

  2. • No style <View android:background=“#FF0000” /> • Style <!--- some_layout.xml

    --> <View style="@style/MyStyle" /> <!--- styles.xml -->
 <style name="MyStyle">
 <item name="android:background">#FF0000</item>
 </style>
  3. When to style • Semantically identical Views • All styled

    Views should change at once
  4. When NOT to style • Single-use styles • Coincidentally using

    the same attributes <TextView
 android:id="@+id/title"
 android:textColor="@color/blue_200"
 android:textColorHint=“@color/grey_500" />
 
 <TextView
 android:id="@+id/body"
 android:textColor="@color/blue_200"
 android:textColorHint=“@color/grey_500" />
  5. When NOT to style • Single-use styles • Coincidentally using

    the same attributes <TextView
 android:id="@+id/title"
 android:textColor="@color/blue_200"
 android:textColorHint=“@color/grey_500" />
 
 <TextView
 android:id="@+id/body"
 android:textColor="@color/blue_200"
 android:textColorHint=“@color/grey_500" />
  6. When NOT to style • Single-use styles • Coincidentally using

    the same attributes <TextView
 android:id="@+id/title"
 android:textColor="@color/blue_200"
 android:textColorHint=“@color/grey_500" />
 
 <TextView
 android:id="@+id/body"
 android:textColor="@color/blue_200"
 android:textColorHint=“@color/grey_500" />
  7. static final int NUM_COLUMNS = 3;
 
 static final int

    NUM_RETRIES = 3; static final int NUM_THREE = 3;
  8. // static final int NUM_COLUMNS = 3;
 
 // static

    final int NUM_RETRIES = 3;
 static final int NUM_THREE = 3;
  9. No style? <ImageView
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:scaleType="centerCrop"
 android:src="@drawable/image"
 /> No problem!

  10. None
  11. None
  12. Inheritance

  13. • Parent <style name="Parent" /> • Explicit child <style name="Child"

    parent="Parent" /> • Implicit child <style name="Parent.Child" />
  14. Custody Battle <style name="Implicit" />
 
 <style name="Explicit" /> <style

    name="Implicit.Child" parent="Explicit" /> • Who gets the child? • Choices: • Both • Implicit • Explicit
  15. None
  16. Avoid mixing implicit and explicit parenting

  17. <Button
 style="@style/Widget.Button.Calculator"
 /> <style name="Widget.Button.Calculator"
 parent="Widget.AppCompat.Button.Borderless" />

  18. <Button
 style="@style/Widget.Button.Calculator"
 /> <style name="Widget.Button.Calculator"
 parent="Widget.HahaFooledYou.Sucker" />

  19. • Explicit parent -> dotless child <style name="BorderlessButton"
 parent="Widget.AppCompat.Button.Borderless" />

    • Fake it! <style name="Widget.Button"
 parent="Widget.AppCompat.Button" />
 
 <style name="Widget.Button.Borderless"
 parent="Widget.AppCompat.Button.Borderless" />
  20. Multiple Styles

  21. IMPOSSIBLE …except for TextAppearance! Image source: https://goo.gl/meSNFL

  22. TextAppearance Attributes • textColor • textColorHighlight • textColorHint • textColorLink

    • textSize • textStyle • fontFamily • typeface • textAllCaps • shadowColor • shadowDx • shadowDy • shadowRadius • elegantTextHeight • letterSpacing • fontFeatureSettings
  23. TextAppearance • In action <TextView
 style="@style/MyStyle"
 android:textAppearance="@style/MyText"
 /> • Always

    inherit TextAppearance! <style name="MyText" parent="TextAppearance.AppCompat">
 <item name="android:textColor">#F00</item>
 </style>
  24. Themes! • Write a whole lot of UX code at

    once! • Setup defaults for everything! • Activity-level theming! • Configure system-created Views! • Theme swapping!
  25. Themes vs. Styles • Same thing! <style name="Style">
 <item name="android:background">#FF0000</item>


    </style> <style name="Theme">
 <item name="android:statusBarColor">@color/blue_200</item>
 </style> • Different scope • Different attributes
  26. Do not mix up styles and themes

  27. Themes in Manifest • Application <application
 android:theme="@style/Theme.AppCompat"> • Activity <activity


    android:theme="@style/Theme.AppCompat.Light">
  28. Applying to View <Toolbar
 android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
 app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
 />

  29. None
  30. Use AppCompat

  31. Use AppCompat • Material on all devices • Baseline themes/styles

    • Enables View theming pre-Lollipop • …And more!
  32. Window Attributes <style name="AppTheme" parent="Theme.AppCompat">
 <item name="android:windowBackground">@color/background</item>
 <item name="android:statusBarColor">@color/blue_200</item>
 <item

    name="android:windowFullscreen">true</item>
 </style>
  33. Color Attributes <style name="ColorTheme" parent="Theme.AppCompat">
 <item name="colorPrimary">#F00</item>
 <item name="colorPrimaryDark">#0F0</item>
 <item

    name="colorControlNormal">#00F</item>
 </style>
  34. Default Styles <style name="AppTheme" parent="Theme.AppCompat">
 <item name="buttonStyle">@style/MyButton</item>
 <item name="android:spinnerItemStyle">@style/MySpinnerItem</item>
 


    <item name="android:textAppearance">@style/MyText</item>
 <item name="android:textAppearanceInverse">@style/MyTextInverse</item>
 </style>
  35. Resource Attributes <style name="AttrTheme" parent="Theme.AppCompat">
 <item name="selectableItemBackground">@drawable/bg</item>
 </style> <!-- some_layout.xml

    -->
 <Button android:background="?attr/selectableItemBackground" />
  36. Resource Attributes <style name="AttrTheme" parent="Theme.AppCompat">
 <item name="selectableItemBackground">@drawable/bg</item>
 </style> <!-- some_layout.xml

    -->
 <Button android:background="?attr/selectableItemBackground" />
  37. Namespacing • Official attributes <style name="MyTheme">
 <item name="android:colorPrimary">#000</item>
 </style> •

    Custom attributes <style name="MyTheme" parent="Theme.AppCompat">
 <item name="colorPrimary">#000</item>
 </style> v21 only appcompat magic
  38. Finding Attributes • Most difficult part of themes • Anyone

    can create attributes • Anything can use attributes
  39. Attributes in XML • Look for ?attr or ?android:attr <Button

    android:background="?attr/selectableItemBackground" />
  40. Individual Attributes • Look for resolveAttribute() context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true); attribute

  41. View Style Attributes • Look for obtainStyledAttributes() TypedArray a =

    context.obtainStyledAttributes(attrs,
 com.android.internal.R.styleable.ImageView, defStyleAttr, defStyleRes); • Investigate TypedArray usage int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255); attribute default
  42. What color is what?

  43. Debug Color Theme

  44. Color By Numbers https://goo.gl/BPNhp1

  45. HierarchyViewer

  46. Dump Theme

  47. Recipe for Sanity • Use AppCompat • Modify theme first

    • Reference theme attributes • Apply themes to Views when necessary • Use styles wisely
  48. Resource Qualifiers

  49. <style name="MyTheme" parent="Theme.AppCompat">
 <item name="android:windowBackground">@color/bg_window</item>
 </style> <!-- values/colors.xml -->
 <color

    name="bg_window">#FF0000</color>
 
 <!-- values-v21/colors.xml -->
 <color name="bg_window">#0000FF</color>
  50. <!-- values/styles.xml -->
 <style name="BaseToolbar" />
 
 <!-- values-v21/styles.xml -->


    <style name="BaseToolbar">
 <item name="android:elevation">4dp</item>
 </style> <!-- values/styles.xml -->
 <style name="Toolbar" parent="BaseToolbar" /> <!-- values/styles.xml -->
 <style name="BaseToolbar" />
 
 <!-- values-v21/styles.xml -->
 <style name="BaseToolbar">
 <item name="android:elevation">4dp</item>
 </style>
  51. Qualifier Triangle values/Theme values-v21/Theme Theme.Used qualifier modifications what is actually

    used
  52. Qualifier Diamond values/Theme.Platform values-v21/Theme.Platform Theme.Platform.Used values/Theme attributes for everyone what

    is actually used qualifier modifications
  53. Custom Attributes <!-- values/attrs.xml -->
 <attr name="myAttribute" format="dimension" />
 


    <!-- values/themes.xml -->
 <style name="MyTheme" parent="Theme.AppCompat">
 <item name="myAttribute">4dp</item>
 </style>
 
 <!-- values/styles.xml -->
 <style name="MyStyle">
 <item name="android:padding">?attr/myAttribute</item>
 </style>
  54. Custom Attributes <!-- values/attrs.xml -->
 <attr name="myAttribute" format="dimension" />
 


    <!-- values/themes.xml -->
 <style name="MyTheme" parent="Theme.AppCompat">
 <item name="myAttribute">4dp</item>
 </style>
 
 <!-- values/styles.xml -->
 <style name="MyStyle">
 <item name="android:padding">?attr/myAttribute</item>
 </style>
  55. Custom Attributes <!-- values/attrs.xml -->
 <attr name="myAttribute" format="dimension" />
 


    <!-- values/themes.xml -->
 <style name="MyTheme" parent="Theme.AppCompat">
 <item name="myAttribute">4dp</item>
 </style>
 
 <!-- values/styles.xml -->
 <style name="MyStyle">
 <item name="android:padding">?attr/myAttribute</item>
 </style>
  56. Dynamic Text Appearance myTextView.setTextAppearance(context, R.style.TextAppearance_AppCompat);

  57. Dynamic Styles public View(Context context, AttributeSet attrs, int defStyleAttr, int

    defStyleRes) themed context layout attributes default style (v21+) default style attribute (from theme, e.g. buttonStyle)
  58. Dynamic Styles • Context carries theme • ContextThemeWrapper replaces parts

    of theme Context themedContext = new ContextThemeWrapper(baseContext, R.style.MyTheme);
 
 // Use in LayoutInflater
 View view = LayoutInflater.from(themedContext) .inflate(R.layout.my_layout, null);
 
 // Use in View constructor
 View view = new View(themedContext);
  59. Dynamic Theming • setTheme() • Call before setContentView() • Otherwise,

    restart Activity
  60. Thank You! • @danlew42 • +DanielLew • http://danlew.net • Color

    debug theme: https://goo.gl/BPNhp1