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

AppCompat and Material : What the theme

Saurabh
December 07, 2019

AppCompat and Material : What the theme

Wondered how the platform decides to use a Button or an AppCompatButton or a MaterialButton? Or how to change the color of a seekBar or the colors of a dialog button?

This talk will dive deep into Themes and Styles. It will cover when to use a style, when to use a theme and what are theme overlays. We'll also unravel which theme attributes control the appearance of views and where to look for supported view attributes. Finally, we'll look at the new Material Design Components for Android.

Original Deck with Animations and Gifs: http://bit.ly/whatTheThemeSlides

Follow me on Twitter for more content: https://twitter.com/saurabh_arora90

Saurabh

December 07, 2019
Tweet

More Decks by Saurabh

Other Decks in Programming

Transcript

  1. Why? • Reusable UI code • Make redesign easier •

    Build a design system • Answer questions – “How to change track color of Seekbar?” @saurabh_arora90
  2. <style name="Widget.DevFest.Button" parent=”…"> <item name="backgroundTint">@color/upsell_button_color</item> <item name="android:insetTop">0dp</item> <item name="android:insetBottom">0dp</item> <item

    name="cornerRadius">@dimen/default_button_radius</item> <item name="android:textAllCaps">false</item> </style> styles @saurabh_arora90
  3. <style name="Widget.DevFest.Button" parent=”…"> <item name="backgroundTint">@color/upsell_button_color</item> <item name="android:insetTop">0dp</item> <item name="android:insetBottom">0dp</item> <item

    name="cornerRadius">@dimen/default_button_radius</item> <item name="android:textAllCaps">false</item> </style> styles View Attributes @saurabh_arora90
  4. <style name="Widget.DevFest.Button" parent=”…"> <item name="backgroundTint">@color/upsell_button_color</item> <item name="android:insetTop">0dp</item> <item name="android:insetBottom">0dp</item> <item

    name="cornerRadius">@dimen/default_button_radius</item> <item name="android:textAllCaps">false</item> </style> styles Applicable values @saurabh_arora90
  5. Theme Attributes • Named variables • Associated with a context

    • Assigned value per theme @saurabh_arora90
  6. <style name="Theme.Red" parent=”…"> <item name="colorPrimary">@color/red</item> <item name="colorOnPrimary">@color/white</item> </style> <Button …

    style="@style/Widget.DevFest.Button"/> Button <style name="Theme.Blue" parent=”…"> <item name="colorPrimary">@color/blue</item> <item name="colorOnPrimary">@color/black</item> </style> Button @saurabh_arora90
  7. <declare-styleable name="AppCompatTheme"> <attr format="reference" name="toolbarStyle"/> <attr format="reference" name="imageButtonStyle"/> <attr format="reference"

    name="alertDialogStyle"/> <attr format="reference" name="autoCompleteTextViewStyle"/> <attr format="reference" name="buttonStyle"/> <attr format="reference" name="checkboxStyle"/> <attr format="reference" name="editTextStyle"/> <attr format="reference" name="radioButtonStyle"/> <attr format="reference" name="ratingBarStyle"/> <attr format="reference" name="seekBarStyle"/> <attr format="reference" name="spinnerStyle"/> <attr format="reference" name="switchStyle"/> <attr format="reference" name="listMenuViewStyle"/> ........ </declare-styleable>
  8. public class Button extends TextView { public Button(Context context) {

    this(context, null); } public Button(Context context, AttributeSet attrs) { this(context, attrs, com.android.internal.R.attr.buttonStyle); } public Button(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public Button(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public CharSequence getAccessibilityClassName() { return Button.class.getName(); } @Override public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { if (getPointerIcon() == null && isClickable() && isEnabled()) { return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND); } return super.onResolvePointerIcon(event, pointerIndex); } }
  9. <style name="Base.V7.Theme.AppCompat" parent=”…"> <item name="buttonStyle">@style/Widget.AppCompat.Button</item> @saurabh_arora90 <style name="Base.Widget.AppCompat.Button" parent="android:Widget"> <item

    name="android:background">@drawable/abc_btn_default_mtrl_shape</item> <item name="android:textAppearance">?android:attr/textAppearanceButton</item> <item name="android:minHeight">48dip</item> <item name="android:minWidth">88dip</item> <item name="android:focusable">true</item> <item name="android:clickable">true</item> <item name="android:gravity">center_vertical|center_horizontal</item> </style>
  10. theme attributes + view attributes <style name=”Theme.DevFest" parent=”…"> <item name="colorPrimaryDark">@color/teal</item>

    <item name="colorAccent">@color/red</item> <item name="toolbarStyle">@style/Widget.DevFest.Toolbar</item> <item name="android:background">@color/surface_2</item> </style> @saurabh_arora90
  11. Activity ViewGroup View View ViewGroup View theme + style on

    view <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:theme="@style/DevFest" style="@style/Widget.DevFest.Button"/> @saurabh_arora90
  12. <style name="Widget.DevFest.Button" parent=”…"> <item name=”text">Set from Style</item> </style> Order of

    precedence View Style @saurabh_arora90 <Button … style="@style/Widget.DevFest.Button”/> Set from Style
  13. Order of precedence View Style Default Style <Button … />

    @saurabh_arora90 public Button(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.buttonStyle); }
  14. <style name=”Devfest" parent=”…"> <item name=”text">Set from Theme</item> </style> Order of

    precedence View Style Default Style Theme Set from Theme <Button … @saurabh_arora90 Theme
  15. AppCompatViewInflater final View createView(…..) { …… // We need to

    'inject' our tint aware Views in place of the standard framework versions switch (name) { case "TextView": view = createTextView(context, attrs); verifyNotNull(view, name); break; case "ImageView": view = createImageView(context, attrs); verifyNotNull(view, name); break;
  16. case "Button": view = createButton(context, attrs); verifyNotNull(view, name); break; case

    "EditText": view = createEditText(context, attrs); verifyNotNull(view, name); break; case "Spinner": view = createSpinner(context, attrs); verifyNotNull(view, name); break; case "ImageButton": view = createImageButton(context, attrs); verifyNotNull(view, name); break; …….
  17. protected AppCompatTextView createTextView(Context context, AttributeSet attrs) { return new AppCompatTextView(context,

    attrs); } protected AppCompatImageView createImageView(Context context, AttributeSet attrs) { return new AppCompatImageView(context, attrs); } protected AppCompatButton createButton(Context context, AttributeSet attrs) { return new AppCompatButton(context, attrs); } protected AppCompatEditText createEditText(Context context, AttributeSet attrs) { return new AppCompatEditText(context, attrs); } …….
  18. public class AppCompatSeekBar extends SeekBar { public AppCompatSeekBar(Context context) {

    this(context, null); } public AppCompatSeekBar(Context context, AttributeSet attrs) { this(context, attrs, R.attr.seekBarStyle); } @saurabh_arora90
  19. public class AppCompatSeekBar extends SeekBar { public AppCompatSeekBar(Context context) {

    this(context, null); } public AppCompatSeekBar(Context context, AttributeSet attrs) { this(context, attrs, R.attr.seekBarStyle); } @saurabh_arora90
  20. <style name="Base.V7.Theme.AppCompat.Light" parent=”…"> <item name="viewInflaterClass">AppCompatViewInflater</item> <item name="windowNoTitle">false</item> <item name="windowActionBar">true</item> ……

    <item name="seekBarStyle">@style/Widget.AppCompat.SeekBar</item> <item name="buttonStyle">@style/Widget.AppCompat.Button</item> <item name="imageButtonStyle">@style/Widget.AppCompat.ImageButton</item> <item name="buttonBarStyle">@style/Widget.AppCompat.ButtonBar</item> ……..
  21. seekbar_track_material ……. <item> <shape android:shape="rectangle" android:tint="?attr/colorControlActivated"> <corners android:radius="?attr/progressBarCornerRadius" /> <size

    android:height="@dimen/seekbar_track_progress_height_material" /> <solid android:color="@color/white_disabled_material" /> </shape> </item> …….
  22. seekbar_track_material ……. <item> <shape android:shape="rectangle" android:tint="?attr/colorControlActivated"> <corners android:radius="?attr/progressBarCornerRadius" /> <size

    android:height="@dimen/seekbar_track_progress_height_material" /> <solid android:color="@color/white_disabled_material" /> </shape> </item> …….
  23. <style name="Base.V14.Theme.MaterialComponents" parent=”…"> <item name="viewInflaterClass">MaterialComponentsViewInflater</item> <item name="bottomAppBarStyle">@style/Widget.MaterialComponent.BottomAppBar</item> <item name="chipStyle">@style/Widget.MaterialComponent.Chip.Action</item> <item

    name="materialButtonStyle">@style/Widget.MaterialComponent.Button</item> <item name="materialCardViewStyle">@style/Widget.MaterialComponent.CardView</item> <item name="snackbarStyle">@style/Widget.MaterialComponent.Snackbar</item> …… @saurabh_arora90
  24. <style name="Base.V14.Theme.MaterialComponents" parent=”…"> <item name="viewInflaterClass">MaterialComponentsViewInflater</item> <item name="bottomAppBarStyle">@style/Widget.MaterialComponent.BottomAppBar</item> <item name="chipStyle">@style/Widget.MaterialComponent.Chip.Action</item> <item

    name="materialButtonStyle">@style/Widget.MaterialComponent.Button</item> <item name="materialCardViewStyle">@style/Widget.MaterialComponent.CardView</item> <item name="snackbarStyle">@style/Widget.MaterialComponent.Snackbar</item> …… @saurabh_arora90
  25. public class MaterialComponentsViewInflater extends AppCompatViewInflater { @Override protected AppCompatButton createButton

    (…) { return new MaterialButton(….); } @Override protected AppCompatCheckBox createCheckBox (…) { return new MaterialCheckBox(….); } @Override protected AppCompatRadioButton createRadioButton (…) { return new MaterialRadioButton(…); } @Override protected AppCompatTextView createTextView (…) { return new MaterialTextView(…); }
  26. <declare-styleable name="MaterialCardView"> <attr name="android:checkable"/> <attr name="cardForegroundColor" format="color"/> <attr name="checkedIcon"/> <attr

    name="checkedIconTint" format="color"/> <attr name="rippleColor"/> <attr name="state_dragged" format="boolean" /> <attr name="strokeColor"/> <attr name="strokeWidth"/> <attr name="shapeAppearance"/> <attr name="shapeAppearanceOverlay"/> </declare-styleable>
  27. @saurabh_arora90 <style name="DevFest" parent=”…"> <item name="colorPrimaryDark">@color/blue</item> <item name="colorSecondary">@color/teal</item> <item name="colorOnPrimary">@color/white</item>

    <item name="colorOnSecondary">@color/black</item> <item name="colorSurface">@color/gray</item> <item name="colorError">@color/contents_red</item>
  28. @saurabh_arora90 <style name="DevFest" parent="Base"> <item name="textAppearanceHeadline1">@style/TextAppearance.DevFest.Headline1</item> <item name="textAppearanceHeadline2">@style/TextAppearance.DevFest.Headline2</item> <item name="textAppearanceHeadline3">@style/TextAppearance.DevFest.Headline3</item>

    <item name="textAppearanceHeadline4">@style/TextAppearance.DevFest.Headline4</item> <item name="textAppearanceHeadline5">@style/TextAppearance.DevFest.Headline5</item> <item name="textAppearanceSubtitle1">@style/TextAppearance.DevFest.Subtitle1</item> <item name="textAppearanceSubtitle2">@style/TextAppearance.DevFest.Subtitle2</item> <item name="textAppearanceBody1">@style/TextAppearance.DevFest.Body1</item> <item name="textAppearanceBody2">@style/TextAppearance.DevFest.Body2</item> <item name="textAppearanceButton">@style/TextAppearance.DevFest.Button</item> <item name="textAppearanceCaption">@style/TextAppearance.DevFest.Caption</item>
  29. Shape • Rectangular by default • Corner angles and curves

    • Edge angles and curves @saurabh_arora90
  30. shape appearance @saurabh_arora90 <declare-styleable name="ShapeAppearance"> <attr name="cornerSize" format="dimension|fraction"/> <attr name="cornerSizeTopLeft"

    format="dimension|fraction"/> <attr name="cornerSizeTopRight" format="dimension|fraction"/> …… <attr name="cornerFamilyTopLeft" format="enum"> <enum name="rounded" value="0"/> <enum name="cut" value="1"/> </attr> <attr name="cornerFamilyTopRight" format="enum"> <enum name="rounded" value="0"/> <enum name="cut" value="1"/> </attr> …… </declare-styleable>
  31. @saurabh_arora90 <style name="DevFestShapeAppearance"> <item name="cornerFamilyTopRight">cut</item> <item name="cornerFamilyBottomRight">cut</item> <item name="cornerSizeBottomLeft">0dp</item> <item

    name="cornerSizeTopLeft">0dp</item> <item name="cornerSizeBottomRight">180dp</item> <item name="cornerSizeTopRight">180dp</item> </style> <style name="Widget.DevFest.Button" parent=”…"> <item name="shapeAppearance">@style/DevFestShapeAppearance</item> </style>
  32. TL ! DL" • Important to differentiate b/w themes &

    styles • Understand how layout substitution works • Learn where to find theme and view attributes • Use default styling • Time to jump to MDC @saurabh_arora90