Slide 1

Slide 1 text

Developing·Themes· with·Style¬

Slide 2

Slide 2 text

@crafty @chrisbanes

Slide 3

Slide 3 text

<item name="key">value!"item> !"style>

Slide 4

Slide 4 text

<item name="key">value!"item> !"style> Untyped

Slide 5

Slide 5 text

Understanding themes & styles

Slide 6

Slide 6 text

<item name="key">value!"item> !"style>

Slide 7

Slide 7 text

<item name="key">value!"item> !"style>

Slide 8

Slide 8 text

styles themes vs

Slide 9

Slide 9 text

styles themes Map Map

Slide 10

Slide 10 text

<item name="android:gravity">center_horizontal!"item> <item name="android:textAppearance">@style/TextAppearance.CommentAuthor!"item> <item name="android:drawablePadding">@dimen/spacing_micro!"item> !"style> styles

Slide 11

Slide 11 text

styles View Attributes <item name="android:gravity">center_horizontal!"item> <item name="android:textAppearance">@style/TextAppearance.CommentAuthor!"item> <item name="android:drawablePadding">@dimen/spacing_micro!"item> !"style>

Slide 12

Slide 12 text

styles Resources <item name="android:gravity">center_horizontal!"item> <item name="android:textAppearance">@style/TextAppearance.CommentAuthor!"item> <item name="android:drawablePadding">@dimen/spacing_micro!"item> !"style>

Slide 13

Slide 13 text

<item name="android:gravity">center_horizontal!"item> <item name="android:textAppearance">@style/TextAppearance.CommentAuthor!"item> <item name="android:drawablePadding">@dimen/spacing_micro!"item> !"style> styles Attribute Boolean Color Dimension Drawable Float Font Fraction String Resources

Slide 14

Slide 14 text

<item name="colorPrimary">@color/teal_500!"item> <item name="colorSecondary">@color/pink_200!"item> <item name="android:windowBackground">@color/background!"item> !"style> themes

Slide 15

Slide 15 text

themes Theme Attributes <item name=" z colorPrimary ">@color/teal_500!"item> <item name="colorSecondary">@color/pink_200!"item> <item name="android:windowBackground">@color/background!"item> !"style>

Slide 16

Slide 16 text

themes attributes

Slide 17

Slide 17 text

<item name="android:elevation">@dimen/design_appbar_elevation!"item> <item name="android:background">?attr/ colorPrimary !"item> <item name="titleTextColor">?attr/colorOnPrimary!"item> !"style> themes attributes

Slide 18

Slide 18 text

<item name="android:elevation">@dimen/design_appbar_elevation!"item> <item name="android:background">?attr/ colorPrimary !"item> <item name="titleTextColor">?attr/colorOnPrimary!"item> !"style> themes attributes Value for current theme

Slide 19

Slide 19 text

:library ?attr/colorPrimary

Slide 20

Slide 20 text

:library ?attr/colorPrimary colorPrimary = !!" :app

Slide 21

Slide 21 text

:library ?attr/colorPrimary colorPrimary = !!" :app colorPrimary = !!" Theme.App Theme.App.Pro

Slide 22

Slide 22 text

:library ?attr/colorPrimary colorPrimary :app Theme.App Theme.App.Pro colorPrimary colorPrimary colorPrimary

Slide 23

Slide 23 text

Widget.RadioButton Widget.RadioButton.Dark Widget.RadioButton.Pro Widget.RadioButton.Pro.Dark Widget.CheckBox Widget.CheckBox.Dark Widget.CheckBox.Pro Widget.CheckBox.Pro.Dark Widget.Switch Widget.Switch.Dark Widget.Switch.Pro Widget.Switch.Pro.Dark Widget.Button Widget.Button.Dark Widget.Button.Pro Widget.Button.Pro.Dark

Slide 24

Slide 24 text

Widget.Button Widget.Button.Dark Widget.Button.Pro Widget.Button.Pro.Dark Widget.Switch Widget.Switch.Dark Widget.Switch.Pro Widget.Switch.Pro.Dark Widget.CheckBox Widget.CheckBox.Dark Widget.CheckBox.Pro Widget.CheckBox.Pro.Dark Widget.RadioButton Widget.RadioButton.Dark Widget.RadioButton.Pro Widget.RadioButton.Pro.Dark

Slide 25

Slide 25 text

view attributes theme attributes Configuration specific to a single view Semantic variables: provided/varied by theme May be used widely

Slide 26

Slide 26 text

styles themes Map Map

Slide 27

Slide 27 text

styles themes Map Associated with & applied to single view Map Associated with a Context Applied to a hierarchy Overlays ancestors

Slide 28

Slide 28 text

styles Activity ViewGroup ViewGroup View View View

Slide 29

Slide 29 text

styles Activity ViewGroup View View View ViewGroup

Slide 30

Slide 30 text

themes Activity ViewGroup View View View ViewGroup

Slide 31

Slide 31 text

themes Activity ViewGroup View View View ViewGroup

Slide 32

Slide 32 text

themes Activity ViewGroup View View View ViewGroup

Slide 33

Slide 33 text

themes Activity ViewGroup View View View ViewGroup

Slide 34

Slide 34 text

!!$ !!$ themes

Slide 35

Slide 35 text

Theme.Owl.Pink themes <item name="colorPrimary"… <item name="colorSecondary"… !!$

Slide 36

Slide 36 text

Theme.MaterialComponents.Light - Theme.Owl.Pink themes <item name="colorPrimary"… <item name="colorSecondary"… <item name="toolbarStyle"… <item name="materialButtonStyle"… !!$

Slide 37

Slide 37 text

Theme.AppCompat.Light - Theme.MaterialComponents.Light !% Theme.Owl.Pink themes <item name="colorPrimary"… <item name="colorSecondary"… <item name="toolbarStyle"… <item name="materialButtonStyle"… <item name="buttonStyle"… <item name="selectableItemBackground"… !!$

Slide 38

Slide 38 text

Theme.Material.Light - Theme.AppCompat.Light !% Theme.MaterialComponents.Light !!& Theme.Owl.Pink themes <item name="colorPrimary"… <item name="colorSecondary"… <item name="toolbarStyle"… <item name="materialButtonStyle"… <item name="buttonStyle"… <item name="selectableItemBackground"… <item name="textCursorDrawable"… !!$

Slide 39

Slide 39 text

eme.Material.Light Theme.AppCompat.Light Theme.MaterialComponents.Light & Theme.Owl.Pink themes Theme.Material.Light - Theme.AppCompat.Light !% Theme.MaterialComponents.Light !!& Theme.Owl.Blue tyle>

Slide 40

Slide 40 text

eme.Material.Light Theme.AppCompat.Light Theme.MaterialComponents.Light & Theme.Owl.Pink themes Theme.Material.Light - Theme.AppCompat.Light !% Theme.MaterialComponents.Light !!& Theme.Owl.Blue tyle>

Slide 41

Slide 41 text

themes <item name="colorPrimary"… <item name="colorSecondary"… !"style>

Slide 42

Slide 42 text

themes <item name="colorPrimary"… <item name="colorSecondary"… !"style> No Parent

Slide 43

Slide 43 text

themes <item name="colorPrimary"… <item name="colorSecondary"… !"style>

Slide 44

Slide 44 text

Theme.Material.Light - Theme.AppCompat.Light !% Theme.MaterialComponents.Light !!& Theme.Owl.Pink themes ThemeOverlay.Owl.Blue <item name="colorPrimary"… <item name="colorSecondary"… <item name="toolbarStyle"… <item name="materialButtonStyle"… <item name="buttonStyle"… <item name="selectableItemBackground"… <item name="textCursorDrawable"… !"style> <style name="ThemeOverlay.Owl.Blue" parent=""> <item name="colorPrimary"… <item name="colorSecondary"… !"style>

Slide 45

Slide 45 text

Slide 46

Slide 46 text

val color = ContextCompat.getColor( fragmentContext, R.color.foo ) C R A F T Y T I P

Slide 47

Slide 47 text

val color = ContextCompat.getColor( fragmentContext, R.color.foo ) C R A F T Y T I P

Slide 48

Slide 48 text

val color = ContextCompat.getColor( closestView.context, R.color.foo ) C R A F T Y T I P

Slide 49

Slide 49 text

@ColorInt fun Context.getThemeColor( @AttrRes themeAttrId: Int ): Int { return obtainStyledAttributes( intArrayOf(themeAttrId) ).use { it.getColor(0, Color.MAGENTA) } } C R A F T Y T I P

Slide 50

Slide 50 text

val themedContext = ContextThemeWrapper( context, R.style.ThemeOverlay_Owl_Blue ) val inflater = LayoutInflater.from(themedContext) val view = inflater.inflate(!!$) C R A F T Y T I P

Slide 51

Slide 51 text

styles themes Map Associated with & applied to single view Map Associated with a Context Applied to a hierarchy Overlays ancestors

Slide 52

Slide 52 text

styles themes Map Associated with & applied to single view Part of view attribute resolution Map Associated with a Context Applied to a hierarchy Overlays ancestors

Slide 53

Slide 53 text

styles @color/blue!"item> !"style>

Slide 54

Slide 54 text

styles @color/blue!"item> !"style>

Slide 55

Slide 55 text

val ta = context.obtainStyledAttributes(!!$)

Slide 56

Slide 56 text

val ta = context.obtainStyledAttributes(!!$) View Style

Slide 57

Slide 57 text

View Style Default Style

Slide 58

Slide 58 text

BUTTON

Slide 59

Slide 59 text

public Button(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.buttonStyle); } BUTTON

Slide 60

Slide 60 text

public Button(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.buttonStyle); } BUTTON

Slide 61

Slide 61 text

public Button(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.buttonStyle); } BUTTON @style/Widget.Material.Light.Button!"item>

Slide 62

Slide 62 text

C R A F T Y T I P <item name="toolbarStyle">@style/Widget.App.Toolbar!"item> !!$ Make styling opt out

Slide 63

Slide 63 text

C R A F T Y T I P class MyTextView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0, @StyleRes defStyleRes: Int = 0 ) : AppCompatTextView(context, attrs, defStyleAttr)

Slide 64

Slide 64 text

C R A F T Y T I P class MyTextView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0, @StyleRes defStyleRes: Int = 0 ) : AppCompatTextView(context, attrs, defStyleAttr)

Slide 65

Slide 65 text

C R A F T Y T I P class MyTextView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0, @StyleRes defStyleRes: Int = 0 ) : AppCompatTextView(context, attrs, defStyleAttr)

Slide 66

Slide 66 text

C R A F T Y T I P class MyTextView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = android.R.attr.textViewStyle, @StyleRes defStyleRes: Int = 0 ) : AppCompatTextView(context, attrs, defStyleAttr)

Slide 67

Slide 67 text

View Style Default Style

Slide 68

Slide 68 text

View Style Default Style Theme

Slide 69

Slide 69 text

styles themes Map Map Lies!

Slide 70

Slide 70 text

View Style Default Style Theme <item name="android: background">#ff00ff !"item> !!$

Slide 71

Slide 71 text

View Style Default Style Theme <item name="android: forceDarkAllowed">true !"item> !!$ C R A F T Y T I P

Slide 72

Slide 72 text

View Style Default Style Theme

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

Green Style Red Style

Slide 75

Slide 75 text

Green Style Red Style ✓ colorPrimary

Slide 76

Slide 76 text

@color/blue!"item> !"style>

Slide 77

Slide 77 text

Slide 78

Slide 78 text

Slide 79

Slide 79 text

“Don't bring a style to a theme fight” —@crafty

Slide 80

Slide 80 text

styles themes Map Associated with & applied to single view Part of view attribute resolution Map Associated with a Context Applied to a hierarchy Overlays ancestors

Slide 81

Slide 81 text

styles themes <item name="android:background"> ?attr/colorSurface !"item> !!$ <style!# <style name="Theme.App"> <item name="toolbarStyle"> @style/Widget.App.Toolbar !"item> !!$ <style!#

Slide 82

Slide 82 text

Using themes & styles

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

Colors Color tag #01579B

Slide 85

Slide 85 text

#01579B R G B Color tag Colors

Slide 86

Slide 86 text

#8001579B A R G B Color tag Colors

Slide 87

Slide 87 text

#01579B Color tag Colors Easily change the alpha in %

Slide 88

Slide 88 text

#01579B Color tag Colors Modify the color in HSB

Slide 89

Slide 89 text

#01579B Color tag Colors Select a color from the Material palette

Slide 90

Slide 90 text

#01579B Color tag Colors Use the built-in color picker

Slide 91

Slide 91 text

#01579B 
 @color/brand_blue
 Doesn't need to be in same file Color tag Colors

Slide 92

Slide 92 text

Colors Color state lists Stateful wrapper around colors Use same state system as drawables BUTTON

Slide 93

Slide 93 text

BUTTON Colors Color state lists Stateful wrapper around colors Use same state system as drawables state_pressed = true

Slide 94

Slide 94 text

Colors Color state lists Stateful wrapper around colors Use same state system as drawables BUTTON state_enabled = false

Slide 95

Slide 95 text

Colors Color state lists res/color/csl_brand_checked.xml

Slide 96

Slide 96 text

Colors Color state lists

Slide 97

Slide 97 text

Colors Color state lists Default color

Slide 98

Slide 98 text

Colors Color state lists Tip: order the items from most-specific to least-specific CSL selects the first item which matches the state

Slide 99

Slide 99 text

Colors Color state lists Tip: order the items from most-specific to least-specific CSL selects the first item which matches the state

Slide 100

Slide 100 text

Colors Color state lists Tip: order the items from most-specific to least-specific CSL selects the first item which matches the state Will always be selected as it matches all states

Slide 101

Slide 101 text

So why are colors so important?

Slide 102

Slide 102 text

So why are colors so important? They're the basis of (good) styling on Android

Slide 103

Slide 103 text

No content

Slide 104

Slide 104 text

No content

Slide 105

Slide 105 text

<item name="colorPrimary">@color/brand_color</item> <item name="colorPrimaryVariant">@color/brand_color_dark</item> <item name="colorSecondary">@color/hot_pink</item> How does this magic work?

Slide 106

Slide 106 text

@color/hot_pink BUTTON

Slide 107

Slide 107 text

BUTTON @color/green

Slide 108

Slide 108 text

BUTTON @color/red

Slide 109

Slide 109 text

BUTTON @color/red

Slide 110

Slide 110 text

Slide 111

Slide 111 text

Slide 112

Slide 112 text

Slide 113

Slide 113 text

Drawable tinting Added in API 21 (Lollipop) Tints a solid color using a specified blending mode Can be stateful if using a ColorStateList Supported < API 21 in VectorDrawableCompat and DrawableCompat

Slide 114

Slide 114 text

Why fill and tint?

Slide 115

Slide 115 text

Fill != Tint

Slide 116

Slide 116 text

Fill != Tint SRC_IN

Slide 117

Slide 117 text

Fill != Tint Fill (dst) Tint (src) Result #FFFFFFFF SRC_IN #FFFFFFFF null

Slide 118

Slide 118 text

Fill != Tint Fill (dst) Tint (src) Result #FFFFFFFF #FF5384EC SRC_IN #FF5384EC

Slide 119

Slide 119 text

Fill != Tint Fill (dst) Tint (src) Result #FFFF00FF #FF5384EC SRC_IN #FF5384EC

Slide 120

Slide 120 text

Fill != Tint Fill (dst) Tint (src) Result #80FF00FF #FF5384EC SRC_IN #805384EC

Slide 121

Slide 121 text

Fill != Tint Fill (dst) Tint (src) Result #FFFF00FF #805384EC SRC_IN #805384EC

Slide 122

Slide 122 text

Fill != Tint Fill (dst) Tint (src) Result #805384EC SRC_IN #405384EC #80FF00FF

Slide 123

Slide 123 text

Fill != Tint Fill (dst) Tint (src) Result ?attr/colorControlNormal
 #B3FFFFFF SRC_IN #B3FFFFFF #FFFFFF

Slide 124

Slide 124 text

Fill != Tint Fill (dst) Tint (src) Result ?attr/colorControlNormal
 #B3FFFFFF SRC_IN #5AFFFFFF #80FFFFFF

Slide 125

Slide 125 text

Fill != Tint ADD CLEAR DARKEN DST DST_ATOP DST_IN DST_OUT DST_OVER LIGHTEN MULTIPLY OVERLAY SCREEN SRC SRC_ATOP SRC_IN SRC_OUT SRC_OVER XOR

Slide 126

Slide 126 text

Recommendation For drawables with a single color (e.g. icons, backgrounds) 
 
 #1 Fill using a solid color (e.g. black) 
 #2 Tint using your chosen color/attribute

Slide 127

Slide 127 text

Slide 128

Slide 128 text

Slide 129

Slide 129 text

Slide 130

Slide 130 text

BUTTON @color/red

Slide 131

Slide 131 text

BUTTON 0.26 #D6D7D7 ≈ #43D6D7D7

Slide 132

Slide 132 text

ColorStateList Or use AppCompat: Alpha modulation added in API 21 (android:alpha) Can reference theme attributes from API 23 AppCompatResources.getColorStateList()

Slide 133

Slide 133 text

Single item ColorStateLists Tip ... ... Repeat for any colors you need an alpha variant of

Slide 134

Slide 134 text

Single item ColorStateLists Tip res/color/color_on_primary_25.xml

Slide 135

Slide 135 text

Single item ColorStateLists Tip res/color/color_on_primary_25.xml res/color/color_on_primary_50.xml

Slide 136

Slide 136 text

Drawable tinting

Slide 137

Slide 137 text

Drawable tinting Where do our drawables live?

Slide 138

Slide 138 text

Drawable tinting View Where do our drawables live? s

Slide 139

Slide 139 text

Drawable tinting View tinting

Slide 140

Slide 140 text

View tinting Views can override drawable tints

Slide 141

Slide 141 text

res/drawable/ic_bug.xml

Slide 142

Slide 142 text

View tinting Views can override drawable tints

Slide 143

Slide 143 text

View tinting Views can override drawable tints Can also call :
 ImageView.setImageTintList()

Slide 144

Slide 144 text

View tinting Views can override drawable tints Can also call :
 ImageView.setImageTintList()

Slide 145

Slide 145 text

Using colors as backgrounds Gotcha ... Internally, the color is wrapped into a ColorDrawable

Slide 146

Slide 146 text

Gotcha res/color/on_primary_25.xml Crash Using colors as backgrounds

Slide 147

Slide 147 text

res/color/on_primary_25.xml res/drawable/rectangle.xml Using colors as backgrounds Gotcha

Slide 148

Slide 148 text

BUTTON

Slide 149

Slide 149 text

ACCEPT REJECT Reset Settings This will reset your device to factory settings.

Slide 150

Slide 150 text

No content

Slide 151

Slide 151 text

No content

Slide 152

Slide 152 text

No content

Slide 153

Slide 153 text

T H E M E S & S T Y L E S Organisation

Slide 154

Slide 154 text

T H E M E S & S T Y L E S Organisation Chris' opinionated rules on:

Slide 155

Slide 155 text

Rule #1 Use literal names for resources

Slide 156

Slide 156 text

... ... ...

Slide 157

Slide 157 text

... ... ... <item name="colorPrimary">@color/color_primary</item> <item name="colorPrimaryDark">@color/color_primary_dark</item> <item name="colorAccent">@color/color_accent</item> Nein

Slide 158

Slide 158 text

... ... ... Giving semantic meaning to hardcoded values

Slide 159

Slide 159 text

... ... ... Use literal names, relevant to the value

Slide 160

Slide 160 text

... ... ... Use literal names, relevant to the value

Slide 161

Slide 161 text

Interface vs
 Implementation Resources Colors, Dimensions, etc Themes

Slide 162

Slide 162 text

#1 Use literal names for resources Rule #2 Use consistent style names

Slide 163

Slide 163 text

... d

Slide 164

Slide 164 text

... d <item name="colorPrimary">...</item>

Slide 165

Slide 165 text

... d <item name="colorPrimary">...</item> Implicit inheritance

Slide 166

Slide 166 text

<item name="contentInsetStart">...</item>

Slide 167

Slide 167 text

<item name="android:background">...</item> <item name="contentInsetStart">...</item>

Slide 168

Slide 168 text


 <item name="android:background">...</item> <item name="contentInsetStart">...</item> Implicit inheritance

Slide 169

Slide 169 text

Widget.AppName.Toolbar.Green Theme.AppName.Blue

Slide 170

Slide 170 text

Widget.AppName.Toolbar.Green Theme.AppName.Blue Style type

Slide 171

Slide 171 text

Widget.AppName.Toolbar.Green Theme.AppName.Blue Group name Could be your app name, or module

Slide 172

Slide 172 text

Widget.AppName.Toolbar.Green Theme.AppName.Blue Sub-group name Mostly applicable to widget styles. What widget is this for?

Slide 173

Slide 173 text

Widget.AppName.Toolbar.Green Theme.AppName.Blue Variant name Used to distinguish variants of main styles

Slide 174

Slide 174 text

Slide 175

Slide 175 text

Slide 176

Slide 176 text

#1 Use literal names for resources #2 Use consistent names Rule #3 Layer your themes for re-use

Slide 177

Slide 177 text

... values/themes.xml

Slide 178

Slide 178 text

... <!-- Added in API 27 --> <item name="android:windowLightNavigationBar">true</item> values/themes.xml Something something error API level

Slide 179

Slide 179 text

<!-- Many many attributes --> <!-- Added in API 27 --> <item name="android:windowLightNavigationBar">true</item> <!-- Many many attributes --> <!-- Added in API 27 --> <item name="android:windowLightNavigationBar">true</item> values/themes.xml

Slide 180

Slide 180 text

values/themes.xml <!-- Many many attributes --> <!-- Added in API 27 --> <item name="android:windowLightNavigationBar">true</item> values-v27/themes.xml <!-- Many many attributes --> <!-- Added in API 27 --> <item name="android:windowLightNavigationBar">true</item>

Slide 181

Slide 181 text

<!-- Many many attributes --> values/themes.xml <!-- Many many attributes --> <!-- Added in API 27 --> <item name="android:windowLightNavigationBar">true</item> values-v27/themes.xml We now have multiple copies of the same theme

Slide 182

Slide 182 text

We want re-use as much as possible The ideal solution would be something like: @mixin

Slide 183

Slide 183 text

The only tool we really have is inheritance, which means... Layering This is how AppCompat is built We want re-use as much as possible

Slide 184

Slide 184 text

Platform.Theme.MyApp Use only to set API level specific attributes values/themes.xml <!-- Attributes specific to v27 --> values-v27/themes.xml

Slide 185

Slide 185 text

Platform.Theme.MyApp Use only to set API level specific attributes values/themes.xml <!-- Attributes specific to v27 --> values-v27/themes.xml

Slide 186

Slide 186 text

Platform.Theme.MyApp Base.Theme.MyApp Everything common across your themes <!-- Things common across app --> <item name="textAppearanceHeadline1">...</item> <item name="editTextStyle">...</item> values/themes.xml Usually have one of these

Slide 187

Slide 187 text

Platform.Theme.MyApp Base.Theme.MyApp Entry point Can have multiple of these, but KISS Theme.MyApp values/themes.xml values-night/themes.xml <!-- Overrides for dark theme -->

Slide 188

Slide 188 text

Theme.MyApp Platform Base.Theme.MyApp Platform Platform Theme.MyApp values-night values Platform.V27 Platform.V21 Platform.V14 values values-v21 values-v27

Slide 189

Slide 189 text

#1 Use literal names for resources #2 Use consistent names #3 Layer your themes for re-use Rule #4 Split files based on purpose

Slide 190

Slide 190 text

<!-- Customize your theme here. --> <item name="colorPrimary">@color/indigo</item> <item name="colorAccent">@color/indigo</item> <item name="colorControlActivated">?colorPrimary</item> <item name="toolbarStyle">@style/Widget.Toolbar</item> <item name="tabStyle">@style/Widget.IOSched.Tabs</item> <item name="android:textViewStyle">@style/Widget.IOSched.TextView</item> <item name="android:windowBackground">@color/white</item> <item name="android:statusBarColor">@color/status_bar</item> <item name="android:windowLightStatusBar" tools:targetApi="m">true</item> <item name="android:navigationBarColor">@color/indigo_dark</item> <item name="android:textColorTertiary">@color/text_color_tertiary</item> <item name="sessionListKeyline">@dimen/session_keyline</item> <item name="eventFilterViewStyle">@style/Widget.IOSched.EventFilters</item> styles.xml

Slide 191

Slide 191 text

<item name="android:windowSharedElementEnterTransition">@transition/speaker_shared_enter <item name="sessionListKeyline">@dimen/margin_normal</item> <item name="popupTheme">@style/AppTheme.PopupTheme</item> <item name="android:background">@color/white</item> <item name="android:elevation">8dp</item> <item name="android:orientation">vertical</item> <item name="titleTextAppearance">@style/TextAppearance.IOSched.ToolbarTitle</item> <item name="popupTheme">@style/AppTheme.PopupTheme</item> <item name="android:textColor">?android:textColorSecondary</item> @font/google_sans</item> styles.xml

Slide 192

Slide 192 text

<item name="titleTextAppearance">@style/TextAppearance.IOSched.ToolbarTitle</item> <item name="popupTheme">@style/AppTheme.PopupTheme</item> <item name="android:textColor">?android:textColorSecondary</item> @font/google_sans</item> @font/google_sans</item> <item name="android:textStyle">bold</item> ?android:textColorSecondary</item>

Slide 193

Slide 193 text

They've stuck to the rule of keeping each resource type in seperate files styles.xml in styles.xml <dimen> in dimens.xml <string> in strings.xml

Slide 194

Slide 194 text

styles.xml They've stuck to the rule of keeping each resource type in seperate files Not a bad idea, but it quickly leads to huge files

Slide 195

Slide 195 text

Split files based on purpose themes.xml Themes and ThemeOverlays type.xml TextAppearances, text size dimensions styles.xml Widget styles. Only. Easy mode dimens.xml colors.xml strings.xml

Slide 196

Slide 196 text

Split files based on purpose Hard mode themes.xml type.xml styles.xml dimens.xml colors.xml strings.xml shape.xml All resources used for shape appearance sys_ui.xml All booleans, colors used to control system-ui

Slide 197

Slide 197 text

Split files based on purpose Really handy when using qualified overrides

Slide 198

Slide 198 text

#1 Use literal names for resources #2 Use consistent names #3 Layer your themes for re-use #4 Split files based on purpose

Slide 199

Slide 199 text

E X A M P L E Material Design Components

Slide 200

Slide 200 text

No content

Slide 201

Slide 201 text

Typography Shape Color

Slide 202

Slide 202 text

No content

Slide 203

Slide 203 text

colorPrimary #0336ff

Slide 204

Slide 204 text

colorSecondaryVariant #ffc000 colorPrimaryVariant #0035c9 colorSecondary #ffde03 colorPrimary #0336ff

Slide 205

Slide 205 text

colorSecondaryVariant #ffc000 colorSecondary #ffde03 colorPrimaryVariant #0035c9 colorPrimary #0336ff

Slide 206

Slide 206 text

colorSurface #ffffff colorSecondaryVariant #ffc000 colorSecondary #ffde03 colorPrimaryVariant #0035c9 colorPrimary #0336ff

Slide 207

Slide 207 text

colorOnSurface #000000 colorOnSecondary #000000 colorOnPrimary #ffffff colorError #b00020 colorSurface #ffffff colorSecondaryVariant #ffc000 colorSecondary #ffde03 colorPrimaryVariant #0035c9 colorPrimary #0336ff

Slide 208

Slide 208 text

colorOnSurface #000000 colorSurface #ffffff colorOnSecondary #000000 colorSecondary #ffde03 colorOnPrimary #ffffff colorPrimary #0336ff colorError #b00020 colorSecondaryVariant #ffc000 colorPrimaryVariant #0035c9

Slide 209

Slide 209 text

<item name="colorPrimary">@color/owl_blue_700!"item> <item name="colorPrimaryVariant">@color/owl_blue_800!"item> <item name="colorSecondary">@color/owl_yellow_500!"item> <item name="colorSecondaryVariant">@color/owl_yellow_400!"item> !"style>

Slide 210

Slide 210 text

<item name="colorPrimary">@color/owl_blue_700!"item> <item name="colorPrimaryVariant">@color/owl_blue_800!"item> <item name="colorSecondary">@color/owl_yellow_500!"item> <item name="colorSecondaryVariant">@color/owl_yellow_400!"item> !"style>

Slide 211

Slide 211 text

Slide 212

Slide 212 text

C R A F T Y T I P

Slide 213

Slide 213 text

C R A F T Y T I P

Slide 214

Slide 214 text

No content

Slide 215

Slide 215 text

@style/TextAppearance.Owl.Headline1!"item> @style/TextAppearance.Owl.Headline2!"item> @style/TextAppearance.Owl.Headline3!"item> @style/TextAppearance.Owl.Headline4!"item> @style/TextAppearance.Owl.Headline5!"item> @style/TextAppearance.Owl.Headline6!"item> @style/TextAppearance.Owl.Subtitle1!"item> @style/TextAppearance.Owl.Subtitle2!"item> @style/TextAppearance.Owl.Body1!"item> @style/TextAppearance.Owl.Body2!"item> @style/TextAppearance.Owl.Button!"item> @style/TextAppearance.Owl.Caption!"item> @style/TextAppearance.Owl.Overline!"item>

Slide 216

Slide 216 text

Slide 217

Slide 217 text

C R A F T Y T I P

Slide 218

Slide 218 text

No content

Slide 219

Slide 219 text

No content

Slide 220

Slide 220 text

<item name="cornerFamily">rounded!"item> <item name="cornerSize">0px!"item> <item name="cornerSizeTopLeft">@dimen/small_comp_tl_radius!"item> !"style>

Slide 221

Slide 221 text

<item name="cornerFamily">rounded!"item> <item name="cornerSize">0px!"item> <item name="cornerSizeTopLeft">@dimen/small_comp_tl_radius!"item> !"style> rounded | cut

Slide 222

Slide 222 text

@style/ShapeAppearance.Owl.SmallComponent @style/ShapeAppearance.Owl.MediumComponent @style/ShapeAppearance.Owl.LargeComponent

Slide 223

Slide 223 text

<item name="cornerFamily">cut!"item> !"style>

Slide 224

Slide 224 text

<item name="cornerFamily">cut!"item> !"style> <com.google.android.material.card.MaterialCardView !!$ app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Owl.Cut">

Slide 225

Slide 225 text

<item name="shapeAppearance"> ?attr/shapeAppearanceLargeComponent!"item> <item name="shapeAppearanceOverlay"> @style/ShapeAppearanceOverlay.MaterialComponents.BottomSheet!"item> !"style>

Slide 226

Slide 226 text

<item name="shapeAppearance"> ?attr/shapeAppearanceLargeComponent!"item> <item name="shapeAppearanceOverlay"> @style/ShapeAppearanceOverlay.MaterialComponents.BottomSheet!"item> !"style>

Slide 227

Slide 227 text

<item name="shapeAppearance"> ?attr/shapeAppearanceLargeComponent!"item> <item name="shapeAppearanceOverlay"> @style/ShapeAppearanceOverlay.MaterialComponents.BottomSheet!"item> !"style>

Slide 228

Slide 228 text

<item name="shapeAppearance"> ?attr/shapeAppearanceLargeComponent!"item> <item name="shapeAppearanceOverlay"> @style/ShapeAppearanceOverlay.MaterialComponents.BottomSheet!"item> !"style> <style name="ShapeAppearanceOverlay.MaterialComponents.BottomSheet" parent=""> <item name="cornerSizeBottomRight">0dp!"item> <item name="cornerSizeBottomLeft">0dp!"item> !"style>

Slide 229

Slide 229 text

val sheetBackground = MaterialShapeDrawable( ShapeAppearanceModel( lessonsSheet.context, R.style.ShapeAppearance_Owl_MinimizedSheet, 0 !( no overlay !) ) ) C R A F T Y T I P

Slide 230

Slide 230 text

val sheetBackground = MaterialShapeDrawable( ShapeAppearanceModel( lessonsSheet.context, R.style.ShapeAppearance_Owl_MinimizedSheet, 0 !( no overlay !) ) ) sheetBackground.interpolation = ...

Slide 231

Slide 231 text

val sheetBackground = MaterialShapeDrawable( ShapeAppearanceModel( lessonsSheet.context, R.style.ShapeAppearance_Owl_MinimizedSheet, 0 !( no overlay !) ) ) sheetBackground.interpolation = ...

Slide 232

Slide 232 text

No content

Slide 233

Slide 233 text

No content

Slide 234

Slide 234 text

- @color/baseline_purple_500!"item> - @color/baseline_purple_600!"item> + @color/owl_blue_700!"item> + @color/owl_yellow_500!"item> - @style/ShapeAppearance. - @style/ShapeAppearance - @style/ShapeAppearance. + @style/ShapeAppearance. + @style/ShapeAppearance + @style/ShapeAppearance. - @style/TextAppearance.Baselin - @style/TextAppearance.Baselin

Slide 235

Slide 235 text

- @color/baseline_purple_500!"item> - @color/baseline_purple_600!"item> + @color/owl_blue_700!"item> + @color/owl_yellow_500!"item> - @style/ShapeAppearance. - @style/ShapeAppearance - @style/ShapeAppearance. + @style/ShapeAppearance. + @style/ShapeAppearance + @style/ShapeAppearance. - @style/TextAppearance.Baselin - @style/TextAppearance.Baselin j.mp/material-theme-builder

Slide 236

Slide 236 text

E X A M P L E Dark Theme

Slide 237

Slide 237 text

DayNight First, tell AppCompat what mode to use Can be done by calling either: AppCompatDelegate.setDefaultNightMode() getDelegate().setLocalNightMode()

Slide 238

Slide 238 text

<item name="colorPrimary"> @color/my_primary </item>

Slide 239

Slide 239 text

<item name="colorPrimary"> @color/my_primary </item>

Slide 240

Slide 240 text

Job done, right?

Slide 241

Slide 241 text

Job done, right? Not usually

Slide 242

Slide 242 text

Title

Slide 243

Slide 243 text

Title

Slide 244

Slide 244 text

Slide 245

Slide 245 text

Always prefer theme attributes for colors

Slide 246

Slide 246 text

No content

Slide 247

Slide 247 text

No content

Slide 248

Slide 248 text

No content

Slide 249

Slide 249 text

<item name="colorPrimary">@color/indigo_500</item> <item name="colorSecondary">@color/pink_a200</item> ... ...

Slide 250

Slide 250 text

Primary color

Slide 251

Slide 251 text

Primary color ~500 tone in light theme

Slide 252

Slide 252 text

Primary color material.io/tools/color Material Color Tool <= 200 tone in dark theme

Slide 253

Slide 253 text

<item name="colorPrimary">@color/indigo_500</item> <item name="colorSecondary">@color/pink_a200</item> ... ... ... What do we set?

Slide 254

Slide 254 text

We need something to alias between the colors @color/indigo_500 values/colors.xml @color/indigo_200 values-night/colors.xml

Slide 255

Slide 255 text

... ... ... Giving semantic meaning to hardcoded values

Slide 256

Slide 256 text

Theme.MyApp Platform Base.Theme.MyApp Platform Platform Theme.MyApp values-night values Platform.V27 Platform.V21 Platform.V14 values values-v21 values-v27

Slide 257

Slide 257 text

values/themes.xml values-night/themes.xml <item name="colorPrimary">@color/indigo_500</item> <item name="colorPrimary">@color/indigo_200</item>

Slide 258

Slide 258 text

<item name="colorPrimary">@color/indigo_500</item> <item name="colorPrimary">@color/indigo_200</item> values/themes.xml values-night/themes.xml

Slide 259

Slide 259 text

No content

Slide 260

Slide 260 text

Don’t use bright colors for large surfaces because they can emit too much brightness. “

Slide 261

Slide 261 text

No content

Slide 262

Slide 262 text

colorPrimary colorSurface colorPrimarySurface

Slide 263

Slide 263 text

values/attrs.xml

Slide 264

Slide 264 text

values/attrs.xml <item name="colorPrimarySurface">?attr/colorPrimary</item> <item name="colorOnPrimarySurface">?attr/colorOnPrimary</item> values/themes.xml values-night/themes.xml <item name="colorPrimarySurface">?attr/colorSurface</item> <item name="colorOnPrimarySurface">?attr/colorOnSurface</item>

Slide 265

Slide 265 text

<item name="android:background">?attr/colorPrimarySurface</item>

Slide 266

Slide 266 text

<item name="android:background">?attr/colorPrimarySurface</item> <!-- Things common across app --> <item name="bottomNavigationStyle"> @style/Widget.Owl.BottomNavigationView
 </item>

Slide 267

Slide 267 text

No content

Slide 268

Slide 268 text

TL;DR Understand the difference between themes and styles Prefer theme attributes when referencing resources Tint drawables rather than filling Name your resources consistently Layer your themes to easily vary its contents Use Material Theming to express your brand

Slide 269

Slide 269 text

Nick Butcher @crafty @chrisbanes Chris Banes Thanks! Join us at the Google booth for any questions