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

Themes, styles & more: from zero to hero

Themes, styles & more: from zero to hero

Haven’t you ever wanted to globally change the appearance of your EditTexts or the font face of all TextViews in your Android application? Themes and styles have always been at the heart of Android development when it comes to UI design. They have been around since API 1 after all and a lot of the Android features are built around them. But do you even know how themes and styles works? What is an attribute? And can you explain the difference between a style, a theme, a text appearance or a theme overlay?

If you have never heard of styles and themes or are not entirely sure you can answer the questions above, this presentation is made for you. This talk will dive deep into the Android styling and theming system. You will learn how to leverage it to customize your Android application, reduce duplication in your code and make your styles cleaner, more manageable and more reusable.

Cyril Mottier

April 23, 2018
Tweet

More Decks by Cyril Mottier

Other Decks in Programming

Transcript

  1. Themes, styles & more
    From zero to hero
    @cyrilmottier

    View Slide

  2. View Slide

  3. View Slide

  4. Yes, I’ll talk about boring XML
    while everybody talks about
    the trendy stuff like Kotlin.

    View Slide

  5. Yes, I’ll talk about boring XML
    while everybody talks about
    the trendy stuff like Kotlin. Sorry.

    – The guy talking to you

    View Slide

  6. AAPT 2
    \eɪeɪpiːtiː ˈtuː\
    AAPT stands for Android Asset Packaging Tool. It compiles application
    resources (e.g. AndroidManifest.xml, XML files, etc.) into binary assets.
    AAPT also allow clients to view, create, and update Android archives.

    View Slide

  7. The mother of all

    A key-value store
    with zero or more pairs

    View Slide

  8. The mother of all

    A key-value store
    with zero or more pairs

    View Slide

  9. <br/><item name="android:minHeight"><br/>@dimen/grid_size_300<br/></item><br/>

    View Slide

  10. <br/><item name="android:minHeight"><br/>@dimen/grid_size_300<br/></item><br/>
    Style’s name
    in upper camel case
    name="ListItem"

    View Slide

  11. <br/><item name="android:minHeight"><br/>@dimen/grid_size_300<br/></item><br/>
    Key-value
    pair

    @dimen/grid_size_300

    View Slide

  12. <br/><item name="android:minHeight"><br/>@dimen/grid_size_300<br/></item><br/>
    name="android:minHeight"
    Key

    View Slide

  13. <br/><item name="android:minHeight"><br/>@dimen/grid_size_300<br/></item><br/>
    @dimen/grid_size_300
    Value

    View Slide

  14. Keys in styles are called
    attributes

    View Slide

  15. Carry type information
    Belong to a namespace
    Hold optional constraints
    Keys in styles are called
    attributes

    View Slide

  16. ”any” by default
    (i.e. when undefined)
    Attributes
    Format types

    View Slide

  17. boolean
    color
    dimension
    float
    string
    integer
    enum
    flags
    reference
    fraction
    Attributes
    Format types

    View Slide

  18. boolean
    color
    dimension
    float
    string
    integer
    enum
    flags
    reference
    fraction
    Resource types
    Attributes
    Format types

    View Slide

  19. boolean
    color
    dimension
    float
    string
    integer
    enum
    flags
    reference
    fraction
    Special types
    Attributes
    Format types

    View Slide

  20. xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
    Attribute namespace
    Android framework namespace

    View Slide

  21. xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
    Attribute namespace
    Android framework namespace
    xmlns:android="http://schemas.android.com/apk/res/android"

    View Slide

  22. xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
    Attribute namespace
    Android framework namespace
    android
    android
    android

    View Slide

  23. Attribute namespace
    Global namespace schema
    xmlns:app="http://schemas.android.com/apk/"
    app:layout_constraintTop_toTopOf="parent" />

    View Slide

  24. Attribute namespace
    Global namespace schema
    xmlns:app="http://schemas.android.com/apk/"
    app:layout_constraintTop_toTopOf="parent" />
    xmlns:app="http://schemas.android.com/apk/"
    app

    View Slide

  25. Attribute namespace
    Global namespace schema
    xmlns:app="http://schemas.android.com/apk/res-auto"
    app:layout_constraintTop_toTopOf="parent" />
    xmlns:app="http://schemas.android.com/apk/res-auto"
    app

    View Slide

  26. Attribute namespace
    Global namespace schema
    xmlns:app="http://schemas.android.com/apk/res-auto"
    app:layout_constraintTop_toTopOf="parent" />
    xmlns:app="http://schemas.android.com/apk/res-auto"
    Type “appNs” in
    Android Studio
    app

    View Slide

  27. format="reference|color" />

    View Slide

  28. format="reference|color" />
    name="background"
    Attribute’s name

    View Slide

  29. format="reference|color" />
    Pipe-separated
    list of types
    format="reference|color"

    View Slide

  30. format="integer"
    min="1"
    max="12" />

    View Slide

  31. format="integer"
    min="1"
    max="12" />
    Upper/lower bounds only
    with integer typed attributes
    min="1"
    max="12"

    View Slide

  32. format="dimension|enum">



    View Slide

  33. Android comes with a bunch of attributes

    View Slide

  34. textColor
    actionBarStyle
    windowReturnTransition
    text
    src
    Naming
    General convention

    View Slide

  35. textColor
    actionBarStyle
    windowReturnTransition
    text
    src
    Naming
    General convention
    Lower
    camel case

    View Slide

  36. Naming
    Exc. #1: layout attributes
    layout_width
    layout_alignBaseline
    layout_marginHorizonal
    layout_weight
    layout_x

    View Slide

  37. Naming
    Exc. #1: layout attributes
    layout_width
    layout_alignBaseline
    layout_marginHorizonal
    layout_weight
    layout_x
    Prefixed with “layout_”
    then lower camel case

    View Slide

  38. state_focused
    state_checked
    state_enabled
    state_drag_hovered
    state_window_focused
    Naming
    Exc. #2: state attributes

    View Slide

  39. state_focused
    state_checked
    state_enabled
    state_drag_hovered
    state_window_focused
    Naming
    Exc. #2: state attributes
    Prefixed with “state_”
    then snake case

    View Slide

  40. Learn the rules like a pro,
    so you can break them
    like an artist.

    – Pablo Picasso

    View Slide

  41. hand_hour
    hand_minute
    ConstraintLayout
    Readability and ease of use
    AnalogClock
    Legacy & deprecated
    layout_constraintGuide_end
    layout_constraintHeight_max
    layout_constraintTop_toTopOf

    View Slide

  42. Styles can inherit from each other creating a
    style hierarchy

    View Slide

  43. parent="@style/Style.Wars" />

    View Slide

  44. Explicit parent
    parent="@ Style.Wars"
    style/ />

    View Slide

  45. Explicit parent
    parent="@Style.Wars" />

    View Slide

  46. Style.Wars"
    Explicit parent
    parent=" />

    View Slide


  47. View Slide


  48. Implicit parent
    Style.Wars

    View Slide

  49. parent="android:Theme.Material.Light" />

    View Slide

  50. parent="android:Theme.Material.Light" />
    Namespaced parent
    android:

    View Slide

  51. parent="" />

    View Slide

  52. parent="" />
    Parentless style
    parent=""

    View Slide

  53. Shorter is better
    No parent | Implicit parent | Shorter parent form

    View Slide

  54. is a universe of styles
    Android

    View Slide

  55. Text appearances
    is a universe of styles
    Android
    Themes
    Theme overlays
    Styles

    View Slide

  56. Style
    A bag of attributes used to style a View

    View Slide


  57. xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/list_selector"
    android:minHeight="@dimen/grid_size_400"
    android:paddingBottom="@dimen/spacing_100"
    android:paddingLeft="@dimen/spacing_200"
    android:paddingRight="@dimen/spacing_200"
    android:paddingTop="@dimen/spacing_100"
    android:text="@string/about" />

    View Slide


  58. xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/list_selector"
    android:minHeight="@dimen/grid_size_400"
    android:paddingBottom="@dimen/spacing_100"
    android:paddingLeft="@dimen/spacing_200"
    android:paddingRight="@dimen/spacing_200"
    android:paddingTop="@dimen/spacing_100"
    android:text="@string/about" />
    android:background="@drawable/list_selector"
    android:minHeight="@dimen/grid_size_400"
    android:paddingBottom="@dimen/spacing_100"
    android:paddingLeft="@dimen/spacing_200"
    android:paddingRight="@dimen/spacing_200"
    android:paddingTop="@dimen/spacing_100"

    View Slide

  59. <br/><item name="android:background">@drawable/list_selector</item><br/><item name="android:minHeight">@dimen/grid_size_400</item><br/><item name="android:paddingBottom">@dimen/spacing_100</item><br/><item name="android:paddingLeft">@dimen/spacing_200</item><br/><item name="android:paddingRight">@dimen/spacing_200</item><br/><item name="android:paddingTop">@dimen/spacing_100</item><br/>

    View Slide


  60. xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/list_selector"
    android:minHeight="@dimen/grid_size_400"
    android:paddingBottom="@dimen/spacing_100"
    android:paddingLeft="@dimen/spacing_200"
    android:paddingRight="@dimen/spacing_200"
    android:paddingTop="@dimen/spacing_100"
    android:text="@string/about" />

    View Slide


  61. xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    style="@style/ListItem"
    android:text="@string/about" />

    View Slide


  62. xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    style="@style/ListItem"
    android:text="@string/about" />

    View Slide


  63. xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/ListItem"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/about" />

    View Slide

  64. TextAppearance
    Text styling

    View Slide

  65. parent="TextAppearance.AppCompat">

    @font/museo_sans_rounded_500

    @color/blue_dark
    @dimen/font_size_large

    View Slide

  66. parent="TextAppearance.AppCompat">

    @font/museo_sans_rounded_500

    @color/blue_dark
    @dimen/font_size_large

    TextAppearance.
    Prefixed by
    “TextAppearance.”

    View Slide

  67. val tv = findViewById(R.id.text)
    tv.setTextAppearance(R.style.TextAppearance_Title)

    View Slide

  68. val tv = findViewById(R.id.text)
    tv.setTextAppearance(R.style.TextAppearance_Title)
    Modify TextView’s
    text appearance
    tv.setTextAppearance(R.style.TextAppearance_Title)

    View Slide

  69. val spannable = SpannableString("Styles rock!")
    spannable.setSpan(
    TextAppearanceSpan(context, R.style.TextAppearance_Title),
    0, spannable.length,
    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
    textView.text = spannable

    View Slide

  70. val spannable = SpannableString("Styles rock!")
    spannable.setSpan(
    TextAppearanceSpan(context, R.style.TextAppearance_Title),
    0, spannable.length,
    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
    textView.text = spannable
    TextAppearanceSpan(context, R.style.TextAppearance_Title)
    Create a Span using the
    given text appearance

    View Slide

  71. TextAppearance
    Supported attributes
    textColor
    textSize
    textStyle
    typeface
    fontFamily
    textColorHighlight
    textColorHint
    textColorLink
    textAllCaps
    shadowColor
    shadowDx
    shadowDy
    shadowRadius
    elegantTextHeight
    letterSpacing
    fontFeatureSettings

    View Slide

  72. TextAppearance
    TextAppearanceSpan attributes
    textColor
    textSize
    textStyle
    typeface
    fontFamily
    textColorHighlight
    textColorHint
    textColorLink
    textAllCaps
    shadowColor
    shadowDx
    shadowDy
    shadowRadius
    elegantTextHeight
    letterSpacing
    fontFeatureSettings

    View Slide

  73. style="@style/FormHeader"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="@style/TextAppearance.Title"
    android:textColor="@color/colorAccent" />

    View Slide

  74. style="@style/FormHeader"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="@style/TextAppearance.Title"
    android:textColor=“@color/blue_cerulean” />
    android:textAppearance="@style/TextAppearance.Title"
    Set TextView’s
    text appearance

    View Slide

  75. style="@style/FormHeader"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="@style/TextAppearance.Title"
    android:textColor="@color/blue_cerulean" />
    android:textAppearance="@style/TextAppearance.Title"
    Least priority
    (applied first)

    View Slide

  76. style="@style/FormHeader"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="@style/TextAppearance.Title"
    android:textColor="@color/blue_cerulean" />
    style="@style/FormHeader"
    Applied then

    View Slide

  77. style="@style/FormHeader"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="@style/TextAppearance.Title"
    android:textColor="@color/blue_cerulean" />
    android:textColor="@color/blue_cerulean"
    Highest priority

    View Slide

  78. Theme
    Activity-level styling

    View Slide

  79. Theme
    Activity-level styling
    fun Context.setTheme(resId: Int)
    val Context.theme: Resources.Theme

    View Slide

  80. Theme
    Activity-level styling
    fun Context.setTheme(resId: Int)
    val Context.theme: Resources.Theme
    fun Context.setTheme(resId: Int)
    Apply the theme
    to the receiver’s Context

    View Slide

  81. Theme
    Activity-level styling
    fun Context.setTheme(resId: Int)
    val Context.theme: Resources.Theme
    fun Context.setTheme(resId: Int)
    Must be called before
    any View is inflated

    View Slide

  82. android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/Theme.City">


    View Slide

  83. android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/Theme.City">


    android:theme="@style/Theme.City"
    Application’s
    default theme

    View Slide

  84. android:name=".MainActivity"
    android:theme="@style/Theme.City.Deluxe" />

    View Slide

  85. android:name=".MainActivity"
    android:theme="@style/Theme.City.Deluxe" />
    Activity specific theme
    android:theme="@style/Theme.City.Deluxe"

    View Slide

  86. Colors
    android:colorPrimary
    android:textColorPrimary

    View Slide

  87. Window configuration
    android:windowBackground
    android:windowDisablePreview
    Colors
    android:colorPrimary
    android:textColorPrimary

    View Slide

  88. Window configuration
    android:windowBackground
    android:windowDisablePreview
    Colors
    android:colorPrimary
    android:textColorPrimary
    Default widget styles
    android:textViewStyle
    android:progressBarStyle

    View Slide

  89. Window configuration
    android:windowBackground
    android:windowDisablePreview
    Colors
    android:colorPrimary
    android:textColorPrimary
    Default widget styles
    android:textViewStyle
    android:progressBarStyle
    Drawables
    android:selectableItemBackground
    android:listDivider

    View Slide

  90. Drawables
    android:selectableItemBackground
    android:listDivider
    Preferences styles
    android:switchPreferenceStyle
    android:editTextPreferenceStyle
    Window configuration
    android:windowBackground
    android:windowDisablePreview
    Colors
    android:colorPrimary
    android:textColorPrimary
    Default widget styles
    android:textViewStyle
    android:progressBarStyle

    View Slide

  91. Text appearances
    android:textAppearanceSmall
    android:textAppearanceLargeInverse
    Preferences styles
    android:switchPreferenceStyle
    android:editTextPreferenceStyle
    Drawables
    android:selectableItemBackground
    android:listDivider
    Window configuration
    android:windowBackground
    android:windowDisablePreview
    Colors
    android:colorPrimary
    android:textColorPrimary
    Default widget styles
    android:textViewStyle
    android:progressBarStyle

    View Slide

  92. Text appearances
    android:textAppearanceSmall
    android:textAppearanceLargeInverse
    Preferences styles
    android:switchPreferenceStyle
    android:editTextPreferenceStyle
    Misc.
    android:dialogTheme
    android:disabledAlpha
    Drawables
    android:selectableItemBackground
    android:listDivider
    Window configuration
    android:windowBackground
    android:windowDisablePreview
    Colors
    android:colorPrimary
    android:textColorPrimary
    Default widget styles
    android:textViewStyle
    android:progressBarStyle

    View Slide

  93. Theme attributes
    can be referenced in layouts, styles, etc.

    View Slide

  94. <br/><item name=“android:background”><br/>@drawable/list_selector<br/></item><br/><item name="android:minHeight">@dimen/grid_size_400</item><br/><item name="android:paddingBottom">@dimen/spacing_100</item><br/><item name="android:paddingLeft">@dimen/spacing_200</item><br/><item name="android:paddingRight">@dimen/spacing_200</item><br/><item name="android:paddingTop">@dimen/spacing_100</item><br/>

    View Slide

  95. <br/><item name=“android:background”><br/>?android:attr/selectableItemBackground<br/></item><br/><item name="android:minHeight">@dimen/grid_size_400</item><br/><item name="android:paddingBottom">@dimen/spacing_100</item><br/><item name="android:paddingLeft">@dimen/spacing_200</item><br/><item name="android:paddingRight">@dimen/spacing_200</item><br/><item name="android:paddingTop">@dimen/spacing_100</item><br/>

    View Slide

  96. ?android:attr/selectableItemBackground

    View Slide

  97. Indicates a
    theme lookup
    ?android:attr/selectableItemBackground
    ?

    View Slide

  98. Theme attribute
    namespace
    ?android:attr/selectableItemBackground
    android:

    View Slide

  99. Attribute
    lookup
    ?android:attr/selectableItemBackground
    attr/

    View Slide

  100. Theme attribute
    actual name
    ?android:attr/selectableItemBackground
    selectableItemBackground

    View Slide

  101. ?android:selectableItemBackground

    View Slide

  102. ?colorPrimary

    View Slide

  103. fun Context.obtainStyledAttributes(
    set: AttributeSet,
    attrs: IntArray,
    defStyleAttr: Int,
    defStyleRes: Int
    ): TypedArray
    How it works
    Theming is not so magical after all…

    View Slide

  104. View Slide

  105. Theme overlays
    View-level theming

    View Slide

  106. android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:theme="@style/ThemeOverlay.Bazinga">


    View Slide

  107. android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:theme="@style/ThemeOverlay.Bazinga">


    Override the current theme
    with the given theme overlay
    android:theme="@style/ThemeOverlay.Bazinga"

    View Slide

  108. Few notes
    about theme overlays
    Based on ContextThemeWrapper
    A bag of theme attributes
    Propagated to descendants

    View Slide

  109. Compatibility
    Theming on different API levels

    View Slide

  110. with AppCompat
    Theme overlays
    API 21
    API 14 API 23

    View Slide

  111. with AppCompat
    Theme overlays
    Theme attributes
    API 21
    API 14 API 23

    View Slide

  112. with AppCompat
    Theme overlays
    Theme attributes
    in layout & styles
    API 21
    API 14 API 23

    View Slide

  113. with AppCompat
    Theme overlays
    Theme attributes
    in layout & styles
    in Drawables
    API 21
    API 14
    VD & AVD only
    API 23

    View Slide

  114. with AppCompat
    Theme overlays
    Theme attributes
    in layout & styles
    in Drawables
    in ColorStateList
    API 21
    API 14
    with AppCompat
    with AppCompat
    VD & AVD only
    API 23

    View Slide

  115. Theming & tinting
    in the real life

    View Slide

  116. View Slide

  117. View Slide

  118. View Slide

  119. View Slide

  120. layout/list_item_user.xml
    android:id="@+id/title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="@style/TextAppearance.XXH1"
    android:textColor="?zenlyListItemTextColorPrimary" />
    android:id="@+id/subtitle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="@style/TextAppearance.XH3"
    android:textColor="?zenlyListItemTextColorSecondary" />

    View Slide

  121. layout/list_item_user.xml
    android:id="@+id/title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="@style/TextAppearance.XXH1"
    android:textColor="?zenlyListItemTextColorPrimary" />
    android:id="@+id/subtitle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="@style/TextAppearance.XH3"
    android:textColor="?zenlyListItemTextColorSecondary" />
    android:textColor="?zenlyListItemTextColorPrimary"
    android:textColor="?zenlyListItemTextColorSecondary"

    View Slide

  122. android:id="@+id/search_icon"
    android:layout_width="@dimen/grid_size_350"
    android:layout_height="@dimen/grid_size_350"
    android:background="?selectableItemBackgroundBorderless"
    android:scaleType="centerInside"
    android:src="@drawable/ic_search"
    app:tint="?colorControlNormal" />
    layout/fragment_dashboard.xml

    View Slide

  123. android:id="@+id/search_icon"
    android:layout_width="@dimen/grid_size_350"
    android:layout_height="@dimen/grid_size_350"
    android:background="?selectableItemBackgroundBorderless"
    android:scaleType="centerInside"
    android:src="@drawable/ic_search"
    app:tint="?colorControlNormal" />
    layout/fragment_dashboard.xml
    android:background="?selectableItemBackgroundBorderless"
    app:tint="?colorControlNormal" />

    View Slide

  124. values/themes.xml values/theme_overlays.xml
    <br/><item name=“colorControlNormal"><br/>@color/blue_dark<br/></item><br/><item name=“zenlyListItemTextColorPrimary"><br/>@color/white<br/></item><br/><item name=“zenlyListItemTextColorSecondary"><br/>@color/blue_heavy<br/></item><br/><item name=“android:listDivider"><br/>@drawable/divider_blue_medium<br/></item><br/>
    <br/><item name="colorControlNormal"><br/>@color/gray_medium<br/></item><br/><item name="zenlyListItemTextColorPrimary"><br/>@color/blue_dark<br/></item><br/><item name="zenlyListItemTextColorSecondary"><br/>@color/gray_medium<br/></item><br/><item name="android:listDivider"><br/>@drawable/divider_gray_light<br/></item><br/>

    View Slide

  125. <br/><item name="colorControlNormal"><br/>@color/gray_medium<br/></item><br/><item name="zenlyListItemTextColorPrimary"><br/>@color/blue_dark<br/></item><br/><item name="zenlyListItemTextColorSecondary"><br/>@color/gray_medium<br/></item><br/><item name="android:listDivider"><br/>@drawable/divider_gray_light<br/></item><br/>
    values/themes.xml values/theme_overlays.xml
    <br/><item name=“colorControlNormal"><br/>@color/blue_dark<br/></item><br/><item name=“zenlyListItemTextColorPrimary"><br/>@color/white<br/></item><br/><item name=“zenlyListItemTextColorSecondary"><br/>@color/blue_heavy<br/></item><br/><item name=“android:listDivider"><br/>@drawable/divider_blue_medium<br/></item><br/>
    @color/gray_medium
    @color/blue_dark
    @color/gray_medium
    @drawable/divider_gray_light
    @color/blue_dark
    @color/white
    @color/blue_heavy
    @drawable/divider_blue_medium

    View Slide

  126. android:id="@+id/dashboard_bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:theme="@style/ThemeOverlay.Zenly.Light"
    app:behavior_hideable="true"
    app:behavior_peekHeight="360dp"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior">


    layout/fragment_dashboard.xml

    View Slide

  127. android:id="@+id/dashboard_bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:theme="@style/ThemeOverlay.Zenly.Light"
    app:behavior_hideable="true"
    app:behavior_peekHeight="360dp"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior">


    layout/fragment_dashboard.xml
    android:theme="@style/ThemeOverlay.Zenly.Light"

    View Slide

  128. View Slide

  129. Normal mode Night mode

    View Slide

  130. values/themes.xml
    <br/><item name="colorPrimary">@color/blue</item><br/><item name="colorPrimaryDark">@color/blue_dark</item><br/><item name="colorAccent">@color/green</item><br/><item name="colorControlNormal">@color/blue_dark</item><br/><item name="zenlyColorBackground">@color/blue</item><br/><item name="zenlyListItemTextColorPrimary">@color/white</item><br/><item name="zenlyListItemTextColorSecondary">@color/blue_heavy</item><br/><!-- ... --><br/>

    View Slide

  131. values-night/themes.xml
    <br/><item name="colorPrimary">@color/blue_dark</item><br/><item name="colorPrimaryDark">@color/blue_black</item><br/><item name="colorAccent">@color/green</item><br/><item name="colorControlNormal">@color/blue_heavy</item><br/><item name="zenlyColorBackground">@color/blue_dark</item><br/><item name="zenlyListItemTextColorPrimary">@color/white</item><br/><item name="zenlyListItemTextColorSecondary">@color/white_o50</item><br/><!-- ... --><br/>

    View Slide

  132. @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    final int uiMode = AppPrefs.from(this).getUiMode();
    if (uiMode == AppPrefs.UI_MODE_NIGHT) {
    getDelegate().setLocalNightMode(
    AppCompatDelegate.MODE_NIGHT_YES);
    } else {
    getDelegate().setLocalNightMode(
    AppCompatDelegate.MODE_NIGHT_NO);
    }
    super.onCreate(savedInstanceState);
    // ...
    }

    View Slide

  133. Organizing styles
    Good practices for XML clean architecture

    View Slide

  134. <br/><item name="android:navigationBarColor">@color/black_o30</item><br/><item name="android:statusBarColor">@color/black_o30</item><br/><item name="android:windowBackground">@color/white</item><br/><item name="android:windowTranslucentNavigation">true</item><br/>
    values/themes.xml

    View Slide

  135. <br/><item name="android:navigationBarColor">@color/black_o30</item><br/><item name="android:statusBarColor">@color/black_o30</item><br/><item name="android:windowBackground">@color/white</item><br/><item name="android:windowTranslucentNavigation">true</item><br/>
    @color/black_o30
    @color/black_o30
    true
    values/themes.xml
    Lint warnings

    View Slide

  136. <br/><item name="android:windowBackground">@color/white</item><br/>
    values/themes.xml
    <br/><item name="android:navigationBarColor">@color/black_o30</item><br/><item name="android:statusBarColor">@color/black_o30</item><br/><item name="android:windowBackground">@color/white</item><br/><item name="android:windowTranslucentNavigation">true</item><br/>
    values-v21/themes.xml

    View Slide

  137. <br/><item name="android:windowBackground">@color/white</item><br/>
    values/themes.xml
    <br/><item name="android:navigationBarColor">@color/black_o30</item><br/><item name="android:statusBarColor">@color/black_o30</item><br/><item name="android:windowBackground">@color/white</item><br/><item name="android:windowTranslucentNavigation">true</item><br/>
    parent="Theme.AppCompat.Light.NoActionBar"
    parent="Theme.AppCompat.Light.NoActionBar"
    Parent style
    duplication
    values-v21/themes.xml

    View Slide

  138. <br/><item name="android:windowBackground">@color/white</item><br/>
    values/themes.xml
    <br/><item name="android:navigationBarColor">@color/black_o30</item><br/><item name="android:statusBarColor">@color/black_o30</item><br/><item name="android:windowBackground">@color/white</item><br/><item name="android:windowTranslucentNavigation">true</item><br/>
    Items
    duplication
    @color/white
    @color/white
    values-v21/themes.xml

    View Slide

  139. Theme.City
    values values-v21 values-v23
    Base.Theme.City Base.Theme.City Base.Theme.City
    Base.V23.Theme.City
    Base.V21.Theme.City
    Base.V1.Theme.City

    View Slide

  140. Theme.City
    values values-v21 values-v23
    Base.Theme.City Base.Theme.City Base.Theme.City
    Base.V23.Theme.City
    Base.V21.Theme.City
    Base.V1.Theme.City

    View Slide

  141. Theme.City
    values values-v21 values-v23
    Base.Theme.City Base.Theme.City Base.Theme.City
    Base.V23.Theme.City
    Base.V21.Theme.City
    Base.V1.Theme.City

    View Slide

  142. Theme.City
    values values-v21 values-v23
    Base.Theme.City Base.Theme.City Base.Theme.City
    Base.V23.Theme.City
    Base.V21.Theme.City
    Base.V1.Theme.City

    View Slide

  143. Theme.City
    values values-v21 values-v23
    Base.Theme.City Base.Theme.City Base.Theme.City
    Base.V23.Theme.City
    Base.V21.Theme.City
    Base.V1.Theme.City

    View Slide

  144. Theme.City
    values values-v21 values-v23
    Base.Theme.City Base.Theme.City Base.Theme.City
    Base.V23.Theme.City
    Base.V21.Theme.City
    Base.V1.Theme.City
    on API 22

    View Slide

  145. Theme.City
    values values-v21 values-v23
    Base.Theme.City Base.Theme.City Base.Theme.City
    Base.V23.Theme.City
    Base.V21.Theme.City
    Base.V1.Theme.City
    on API 26

    View Slide

  146. values/themes_base.xml
    parent="Theme.AppCompat.Light.NoActionBar">
    @color/white


    View Slide

  147. <br/><item name="android:navigationBarColor">@color/black_o30</item><br/><item name="android:statusBarColor">@color/black_o30</item><br/><item name="android:windowTranslucentNavigation">true</item><br/>

    values-v21/themes_base.xml

    View Slide

  148. values/themes.xml

    View Slide

  149. Prefix Filename
    text_appearances.xml
    themes.xml
    theme_overlays.xml
    TextAppearance.
    Theme.
    ThemeOverlay.
    Text appearances
    Themes
    Theme overlays
    styles_widget.xml
    Widget.
    Widget styles
    styles.xml
    -
    Custom styles

    View Slide

  150. Prefix Filename
    text_appearances_base.xml
    themes_base.xml
    theme_overlays_base.xml
    Base.TextAppearance.
    Base.Theme.
    Base.ThemeOverlay.
    Base text appearances
    Base themes
    Base theme overlays
    styles_widget_base.xml
    Base.Widget.
    Base widget styles
    styles_base.xml
    Base.
    Base custom styles

    View Slide

  151. Thank you!
    @cyrilmottier
    cyrilmottier.com

    View Slide