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. Yes, I’ll talk about boring XML while everybody talks about

    the trendy stuff like Kotlin. Sorry. “ – The guy talking to you
  2. 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.
  3. Learn the rules like a pro, so you can break

    them like an artist. “ – Pablo Picasso
  4. hand_hour hand_minute ConstraintLayout Readability and ease of use AnalogClock Legacy

    & deprecated layout_constraintGuide_end layout_constraintHeight_max layout_constraintTop_toTopOf
  5. <?xml version="1.0" encoding="utf-8"?> <TextView 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"
  6. 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
  7. TextAppearance Supported attributes textColor textSize textStyle typeface fontFamily textColorHighlight textColorHint

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

    textColorLink textAllCaps shadowColor shadowDx shadowDy shadowRadius elegantTextHeight letterSpacing fontFeatureSettings
  9. 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
  10. 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 ⚠
  11. Window configuration android:windowBackground android:windowDisablePreview Colors android:colorPrimary android:textColorPrimary Default widget styles

    android:textViewStyle android:progressBarStyle Drawables android:selectableItemBackground android:listDivider
  12. 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
  13. 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
  14. 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
  15. <style name="ListItem"> <item name=“android:background”> @drawable/list_selector </item> <item name="android:minHeight">@dimen/grid_size_400</item> <item name="android:paddingBottom">@dimen/spacing_100</item>

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

    <item name="android:paddingLeft">@dimen/spacing_200</item> <item name="android:paddingRight">@dimen/spacing_200</item> <item name="android:paddingTop">@dimen/spacing_100</item> </style>
  17. Few notes about theme overlays Based on ContextThemeWrapper A bag

    of theme attributes Propagated to descendants
  18. with AppCompat Theme overlays Theme attributes in layout & styles

    in Drawables API 21 API 14 VD & AVD only API 23
  19. 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
  20. layout/list_item_user.xml <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="@style/TextAppearance.XXH1" android:textColor="?zenlyListItemTextColorPrimary" /> <TextView 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"
  21. values/themes.xml values/theme_overlays.xml <style name="Theme.Zenly" parent="Base.Theme.Zenly"> <item name=“colorControlNormal"> @color/blue_dark </item> <item

    name=“zenlyListItemTextColorPrimary"> @color/white </item> <item name=“zenlyListItemTextColorSecondary"> @color/blue_heavy </item> <item name=“android:listDivider"> @drawable/divider_blue_medium </item> </style> <style name="ThemeOverlay.Zenly.Light"> <item name="colorControlNormal"> @color/gray_medium </item> <item name="zenlyListItemTextColorPrimary"> @color/blue_dark </item> <item name="zenlyListItemTextColorSecondary"> @color/gray_medium </item> <item name="android:listDivider"> @drawable/divider_gray_light </item> </style>
  22. <style name="ThemeOverlay.Zenly.Light"> <item name="colorControlNormal"> @color/gray_medium </item> <item name="zenlyListItemTextColorPrimary"> @color/blue_dark </item>

    <item name="zenlyListItemTextColorSecondary"> @color/gray_medium </item> <item name="android:listDivider"> @drawable/divider_gray_light </item> </style> values/themes.xml values/theme_overlays.xml <style name="Theme.Zenly" parent="Base.Theme.Zenly"> <item name=“colorControlNormal"> @color/blue_dark </item> <item name=“zenlyListItemTextColorPrimary"> @color/white </item> <item name=“zenlyListItemTextColorSecondary"> @color/blue_heavy </item> <item name=“android:listDivider"> @drawable/divider_blue_medium </item> </style> @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
  23. values/themes.xml <style name="Theme.Zenly" parent="Base.Theme.Zenly"> <item name="colorPrimary">@color/blue</item> <item name="colorPrimaryDark">@color/blue_dark</item> <item name="colorAccent">@color/green</item>

    <item name="colorControlNormal">@color/blue_dark</item> <item name="zenlyColorBackground">@color/blue</item> <item name="zenlyListItemTextColorPrimary">@color/white</item> <item name="zenlyListItemTextColorSecondary">@color/blue_heavy</item> <!-- ... --> </style>
  24. values-night/themes.xml <style name="Theme.Zenly" parent="Base.Theme.Zenly"> <item name="colorPrimary">@color/blue_dark</item> <item name="colorPrimaryDark">@color/blue_black</item> <item name="colorAccent">@color/green</item>

    <item name="colorControlNormal">@color/blue_heavy</item> <item name="zenlyColorBackground">@color/blue_dark</item> <item name="zenlyListItemTextColorPrimary">@color/white</item> <item name="zenlyListItemTextColorSecondary">@color/white_o50</item> <!-- ... --> </style>
  25. @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); // ... }
  26. <style name="Theme.City" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:navigationBarColor">@color/black_o30</item> <item name="android:statusBarColor">@color/black_o30</item> <item name="android:windowBackground">@color/white</item> <item

    name="android:windowTranslucentNavigation">true</item> </style> <item name="android:navigationBarColor">@color/black_o30</item> <item name="android:statusBarColor">@color/black_o30</item> <item name="android:windowTranslucentNavigation">true</item> values/themes.xml Lint warnings
  27. <style name="Theme.City" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowBackground">@color/white</item> </style> values/themes.xml <style name="Theme.City" parent="Theme.AppCompat.Light.NoActionBar">

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

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

    <item name="android:navigationBarColor">@color/black_o30</item> <item name="android:statusBarColor">@color/black_o30</item> <item name="android:windowBackground">@color/white</item> <item name="android:windowTranslucentNavigation">true</item> </style> Items duplication <item name="android:windowBackground">@color/white</item> <item name="android:windowBackground">@color/white</item> values-v21/themes.xml
  30. 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
  31. 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