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

Mastering Android Drawables

Mastering Android Drawables

Over the past few years, the quality of apps in the Google Play Store has increased substantially. Developers are taking Android UI seriously and producing beautiful apps made of tons of graphics resources (Bitmaps, 9-patches, shapes, etc.) every day. To avoid developers the pain of handling all types of resources, the Android framework provides the Drawable abstraction.

In this session we will deep dive into the android.graphics.drawable package and how the framework uses it internally to render scalable and responsive UIs. The Drawable notion is essential to the creation of UIs on Android but developers usually only scratch the surface of it. The class will help you to understand how framework-provided and custom Drawables can be used to make both your code cleaner and your app better, smoother and more polished.

Cyril Mottier

March 28, 2013
Tweet

More Decks by Cyril Mottier

Other Decks in Programming

Transcript

  1. Mtg
    ANDROID DRAWABLES
    wh Cyril Moi

    View Slide

  2. Tnk y f comg

    View Slide

  3. @cyrilmottier
    cyrilmottier.com

    View Slide

  4. View Slide

  5. hp://w.capaetra.com/jobs

    View Slide

  6. An troduc 
    ANDROID DRAWABLES?

    View Slide

  7. An abstrac   ty
     c be drawn  a
    Cv
    Drawable


    Canvas

    View Slide

  8. View
    Ctry  a Drawable
    don’t al wh msu/yt,  ly
    draw(Canvas)

    View Slide

  9. View Slide

  10. View Slide

  11. getIntrinsicWidth()
    getIntrinsicHeight()

    View Slide

  12. View Slide

  13. getBounds()

    View Slide

  14. View Slide

  15. setState(int[])

    View Slide

  16. setLevel(int)

    View Slide

  17. Drawable
    Usg a from XML ...

    View Slide

  18. 1 2 android:id="@+id/image_view"
    3 android:layout_width="wrap_content"
    4 android:layout_height="wrap_content"
    5 android:src="@drawable/ic_share" />

    View Slide

  19.  from Java ...

    View Slide

  20. 1 ImageView imageView = (ImageView)
    2 findViewById(R.id.image_view);
    3
    4 imageView.setImageResource(R.drawable.ic_share);

    View Slide

  21. Tt’s a folks!

    View Slide

  22. Tt’s a folks!
    wt k ...

    View Slide

  23. T Drawab
    LOADING MECHANISM

    View Slide

  24. A sg meod  ru m a

    View Slide

  25. Drawable getDrawable(int)
    android.content.res.Resources
    In

    View Slide

  26. Drawable object?
    Wt   turn

    View Slide

  27. Drawable

    View Slide

  28. Drawable
    BitmapDrawable ColorDrawable

    View Slide

  29. Drawable
    BitmapDrawable DrawableContainer
    ColorDrawable

    View Slide

  30. Drawable
    BitmapDrawable DrawableContainer
    ColorDrawable
    StateListDrawable LayerDrawable

    View Slide

  31. Drawable
    BitmapDrawable DrawableContainer
    ColorDrawable
    StateListDrawable LayerDrawable

    View Slide

  32. getDrawable(int) impmtn
    T

    View Slide

  33. File ends
    with «.xml»

    View Slide

  34. Inflate from
    XML
    File ends
    with «.xml»
    YES

    View Slide

  35. Inflate from
    XML
    File ends
    with «.xml»
    Create from stream
    to jpg/png
    YES NO

    View Slide

  36. Inflate from
    XML
    File ends
    with «.xml»
    Create from stream
    to jpg/png
    Return the
    new Drawable
    YES NO

    View Slide

  37. Inflate from
    XML
    File ends
    with «.xml»
    Create from stream
    to jpg/png
    Return the
    new Drawable
    YES NO

    View Slide

  38. Let’s py!

    View Slide

  39. 1 @Override
    2 public void onCreate(Bundle savedInstanceState) {
    3 super.onCreate(savedInstanceState);
    4
    5 Resources r = getResources();
    6 Drawable d1 = r.getDrawable(R.drawable.ic_launcher);
    7 Drawable d2 = r.getDrawable(R.drawable.ic_launcher);
    8
    9 Log.d(LOG_TAG, "d1: " + d1);
    10 Log.d(LOG_TAG, "d2: " + d2);
    11 }

    View Slide

  40. 03-23 16:39:29.745: DEBUG/Activity(19742): d1:
    [email protected]
    03-23 16:39:29.745: DEBUG/Activity(19742): d2:
    [email protected]
    tputs

    View Slide

  41. 03-23 16:39:29.745: DEBUG/Activity(19742): d1:
    [email protected]
    03-23 16:39:29.745: DEBUG/Activity(19742): d2:
    [email protected]
    tputs

    View Slide

  42. 03-23 16:39:29.745: DEBUG/Activity(19742): d1:
    [email protected]
    03-23 16:39:29.745: DEBUG/Activity(19742): d2:
    [email protected]
    tputs

    View Slide

  43. View Slide

  44. getDrawable(int) always turns
    a new Drawab

    View Slide

  45. but ...

    View Slide

  46. 1 @Override
    2 public void onCreate(Bundle savedInstanceState) {
    3 super.onCreate(savedInstanceState);
    4
    5 Resources r = getResources();
    6 Drawable d1 = r.getDrawable(R.drawable.ic_launcher);
    7 Drawable d2 = r.getDrawable(R.drawable.ic_launcher);
    8
    9 Log.d(LOG_TAG, "d1.cs: " + d1.getConstantState());
    10 Log.d(LOG_TAG, "d2.cs: " + d2.getConstantState());
    11 }

    View Slide

  47. 03-23 16:42:51.345: DEBUG/Activity(19742): d1.cs:
    [email protected]
    03-23 16:42:51.345: DEBUG/Activity(19742): d2.cs:
    [email protected]
    tputs

    View Slide

  48. 03-23 16:42:51.345: DEBUG/Activity(19742): d1.cs:
    [email protected]
    03-23 16:42:51.345: DEBUG/Activity(19742): d2.cs:
    [email protected]
    tputs

    View Slide

  49. 03-23 16:42:51.345: DEBUG/Activity(19742): d1.cs:
    [email protected]
    03-23 16:42:51.345: DEBUG/Activity(19742): d2.cs:
    [email protected]
    tputs

    View Slide

  50. Drawables
    ConstantState
    s ir

    View Slide

  51. View Slide

  52. See http://www.curious-creature.org/2009/05/02/drawable-mutations/ for more information
    ConstantState may be a probm
    somem

    View Slide

  53. Drawable.mutate()
    Cag
    ConstantState
    copi 

    View Slide

  54. View Slide

  55. Some
    NICE GOTCHAS

    View Slide

  56. StateListDrawable












    LevelListDrawable
    LayerDrawable
    TransitionDrawable
    ColorDrawable
    GradientDrawable
    ScaleDrawable
    ClipDrawable
    RotateDrawable
    AnimationDrawable
    InsetDrawable
    BitmapDrawable
    NinePatchDrawable

    View Slide

  57. StateListDrawable












    LevelListDrawable
    LayerDrawable
    TransitionDrawable
    ColorDrawable
    GradientDrawable
    ScaleDrawable
    ClipDrawable
    RotateDrawable
    AnimationDrawable
    InsetDrawable
    BitmapDrawable
    NinePatchDrawable
    Resources.NotFoundException

    View Slide

  58. 1
    2 3 xmlns:android="http://schemas.android.com/apk/res/android"
    4 android:src="@drawable/stripes_bitmap" />

    View Slide

  59. 1
    2 3 xmlns:android="http://schemas.android.com/apk/res/android"
    4 android:src="@drawable/stripes_bitmap" />

    View Slide

  60. 1
    2 3 xmlns:android="http://schemas.android.com/apk/res/android"
    4 android:src="@drawable/stripes_bitmap"
    5 android:gravity="center" />

    View Slide

  61. 1
    2 3 xmlns:android="http://schemas.android.com/apk/res/android"
    4 android:src="@drawable/stripes_bitmap"
    5 android:tileMode="repeat" />

    View Slide

  62. 1
    2 3 xmlns:android="http://schemas.android.com/apk/res/android"
    4 android:src="@drawable/stripes_bitmap"
    5 android:tileMode="mirror" />

    View Slide

  63. 1
    2 3 xmlns:android="http://schemas.android.com/apk/res/android">
    4
    5
    6
    7
    8
    9
    10

    View Slide

  64. 1
    2 3 xmlns:android="http://schemas.android.com/apk/res/android">
    4
    5
    6
    7
    8
    9
    10
    On Jly Bn:

    View Slide

  65. 1
    2 3 xmlns:android="http://schemas.android.com/apk/res/android">
    4
    5
    6
    7
    8
    9
    10
    On Ggbad:

    View Slide

  66. View Slide

  67. ColorDrawable  not cli prr 
    Heycomb

    View Slide

  68. 1
    2 3 xmlns:android="http://schemas.android.com/apk/res/android">
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Use a solid col
    GraditDrawab std

    View Slide

  69. android.graphics.drawable
    Have a lk 
    Wt me?

    View Slide

  70. Advc
    DRAWABLE USAGE

    View Slide

  71. Usg a Drawable  a
    custom View  sy

    View Slide

  72. 1 public class DrawableView extends View {
    2 private Drawable mDrawable;
    3
    4 public DrawableView(Context context) { super(context); }
    5
    6 public void setDrawable(Drawable d) {
    7 if (d != mDrawable) {
    8 mDrawable = d;
    9 if (d != null) {
    10 updateDrawableBounds();
    11 }
    12 }
    13 }
    14
    15 /** Update Drawable bounds with Drawable.setBounds(int, int, int, int) */
    16 private void updateDrawableBounds() { /* ... */ }
    17
    18 @Override
    19 protected void onDraw(Canvas canvas) {
    20 super.onDraw(canvas);
    21 if (mDrawable != null) {
    22 mDrawable.draw(canvas);
    23 }
    24 }
    25 }

    View Slide

  73. AnimationDrawable
    Let’s use 
    wh  new View

    View Slide

  74. C e y wi ...

    View Slide

  75. View Slide

  76. Drawable.Callback
    T sw:

    View Slide

  77. 1 public interface Callback {
    2 public void invalidateDrawable(Drawable who);
    3
    4 public void scheduleDrawable(Drawable who,
    5 Runnable what,
    6 long when);
    7
    8 public void unscheduleDrawable(Drawable who,
    9 Runnable what);
    10 }

    View Slide

  78. 1 public class View implements Drawable.Callback,
    2 KeyEvent.Callback,
    3 AccessibilityEventSource {
    4
    5 /** android.view.View code */
    6
    7 }

    View Slide

  79. verifyDrawable(Drawable)
    Just use

    View Slide

  80. 1 public void setDrawable(Drawable d) {
    2 if (d != mDrawable) {
    3 if (mDrawable != null) {
    4 mDrawable.setCallback(null);
    5 }
    6 mDrawable = d;
    7 if (d != null) {
    8 d.setCallback(this);
    9 updateDrawableBounds();
    10 }
    11 }
    12 }
    13
    14 @Override
    15 protected boolean verifyDrawable(Drawable who) {
    16 return super.verifyDrawable(who) || who == mDrawable;
    17 }
    Ungt  pvus
    caback  avoid aks

    View Slide

  81. 1 public void setDrawable(Drawable d) {
    2 if (d != mDrawable) {
    3 if (mDrawable != null) {
    4 mDrawable.setCallback(null);
    5 }
    6 mDrawable = d;
    7 if (d != null) {
    8 d.setCallback(this);
    9 updateDrawableBounds();
    10 }
    11 }
    12 }
    13
    14 @Override
    15 protected boolean verifyDrawable(Drawable who) {
    16 return super.verifyDrawable(who) || who == mDrawable;
    17 }
    Regt  cut view
      new caback

    View Slide

  82. 1 public void setDrawable(Drawable d) {
    2 if (d != mDrawable) {
    3 if (mDrawable != null) {
    4 mDrawable.setCallback(null);
    5 }
    6 mDrawable = d;
    7 if (d != null) {
    8 d.setCallback(this);
    9 updateDrawableBounds();
    10 }
    11 }
    12 }
    13
    14 @Override
    15 protected boolean verifyDrawable(Drawable who) {
    16 return super.verifyDrawable(who) || who == mDrawable;
    17 }
    D’t fget  ca 
    sup meod

    View Slide

  83. Fg
    VIEW HIERARCHY

    View Slide

  84. disclaimer: this is an imaginary screen

    View Slide

  85. 1 2 android:name="LoginActivity"
    3 android:label="@string/app_name"
    4 android:theme="@android:style/Theme.Holo.Light.NoActionBar">
    5
    6
    7
    8
    9
    AndroidManifest.xml
    In

    View Slide

  86. 1
    2 3 android:layout_width="match_parent"
    4 android:layout_height="match_parent"
    5 android:background="@color/app_background"
    6 android:padding="8dp">
    7
    8 9 android:layout_width="wrap_content"
    10 android:layout_height="wrap_content"
    11 android:layout_marginBottom="24dp"
    12 android:layout_gravity="center"
    13 android:src="@drawable/logo" />
    14
    15 16 android:layout_width="match_parent"
    17 android:layout_height="48dp"
    18 android:layout_gravity="bottom"
    19 android:orientation="horizontal">
    20
    21 22 android:layout_width="0dp"
    23 android:layout_height="fill_parent"
    24 android:layout_weight="1"
    25 android:text="@string/sign_up" />
    26
    27 28 android:layout_width="0dp"
    29 android:layout_height="fill_parent"
    30 android:layout_weight="1"
    31 android:text="@string/sign_in" />
    32
    33
    34
    35

    View Slide

  87. 1
    2 3 android:layout_width="match_parent"
    4 android:layout_height="match_parent"
    5 android:background="@color/app_background"
    6 android:padding="8dp">
    7
    8 9 android:layout_width="wrap_content"
    10 android:layout_height="wrap_content"
    11 android:layout_marginBottom="24dp"
    12 android:layout_gravity="center"
    13 android:src="@drawable/logo" />
    14
    15 16 android:layout_width="match_parent"
    17 android:layout_height="48dp"
    18 android:layout_gravity="bottom"
    19 android:orientation="horizontal">
    20
    21 22 android:layout_width="0dp"
    23 android:layout_height="fill_parent"
    24 android:layout_weight="1"
    25 android:text="@string/sign_up" />
    26
    27 28 android:layout_width="0dp"
    29 android:layout_height="fill_parent"
    30 android:layout_weight="1"
    31 android:text="@string/sign_in" />
    32
    33
    34
    35
    Use  almt uss rt
    FrameLayt  hold 
    backgr

    View Slide

  88. 1
    2 3 android:layout_width="match_parent"
    4 android:layout_height="match_parent"
    5 android:background="@color/app_background"
    6 android:padding="8dp">
    7
    8 9 android:layout_width="wrap_content"
    10 android:layout_height="wrap_content"
    11 android:layout_marginBottom="24dp"
    12 android:layout_gravity="center"
    13 android:src="@drawable/logo" />
    14
    15 16 android:layout_width="match_parent"
    17 android:layout_height="48dp"
    18 android:layout_gravity="bottom"
    19 android:orientation="horizontal">
    20
    21 22 android:layout_width="0dp"
    23 android:layout_height="fill_parent"
    24 android:layout_weight="1"
    25 android:text="@string/sign_up" />
    26
    27 28 android:layout_width="0dp"
    29 android:layout_height="fill_parent"
    30 android:layout_weight="1"
    31 android:text="@string/sign_in" />
    32
    33
    34
    35
    T logo c be csid
      backgr

    View Slide

  89. 1
    2 3 android:layout_width="match_parent"
    4 android:layout_height="match_parent"
    5 android:background="@color/app_background"
    6 android:padding="8dp">
    7
    8 9 android:layout_width="wrap_content"
    10 android:layout_height="wrap_content"
    11 android:layout_marginBottom="24dp"
    12 android:layout_gravity="center"
    13 android:src="@drawable/logo" />
    14
    15 16 android:layout_width="match_parent"
    17 android:layout_height="48dp"
    18 android:layout_gravity="bottom"
    19 android:orientation="horizontal">
    20
    21 22 android:layout_width="0dp"
    23 android:layout_height="fill_parent"
    24 android:layout_weight="1"
    25 android:text="@string/sign_up" />
    26
    27 28 android:layout_width="0dp"
    29 android:layout_height="fill_parent"
    30 android:layout_weight="1"
    31 android:text="@string/sign_in" />
    32
    33
    34
    35
    «Sign Up/In» bus e
     ly actual ctt

    View Slide

  90. disclaimer: this is an imaginary screen

    View Slide

  91. disclaimer: this is an imaginary screen

    View Slide

  92. Drawable
    A -b be
    solu ...

    View Slide

  93. 1
    2 3 xmlns:android="http://schemas.android.com/apk/res/android"
    4 android:layout_width="match_parent"
    5 android:layout_height="48dp"
    6 android:layout_gravity="bottom"
    7 android:layout_margin="8dp"
    8 android:orientation="horizontal">
    9
    10 11 android:layout_width="0dp"
    12 android:layout_height="fill_parent"
    13 android:layout_weight="1"
    14 android:text="@string/sign_up" />
    15
    16 17 android:layout_width="0dp"
    18 android:layout_height="fill_parent"
    19 android:layout_weight="1"
    20 android:text="@string/sign_in" />
    21
    22

    View Slide

  94. 1
    2 3 xmlns:android="http://schemas.android.com/apk/res/android">
    4
    5
    6
    7 8 android:color="@color/app_background" />
    9
    10
    11
    12 13 android:bottom="48dp">
    14 15 android:src="@drawable/logo"
    16 android:gravity="center" />
    17
    18
    19
    Backgr col wh
    ct logo  p

    View Slide

  95. 1 2 android:name="LoginActivity"
    3 android:label="@string/app_name"
    4 android:theme="@style/Theme.Default.NoActionBar">
    5
    6
    7
    8
    9
    AndroidManifest.xml
    In

    View Slide

  96. 1
    2
    3
    4 5 name="Theme.Default.NoActionBar"
    6 parent="@android:style/Theme.Holo.Light.NoActionBar">
    7 @drawable/login
    8
    9
    10
    res/values/themes.xml
    In

    View Slide

  97. disclaimer: this is an imaginary screen

    View Slide

  98. disclaimer: this is an imaginary screen

    View Slide

  99. +
    + + +
    +
    + + +
    +
    +
    + + + + +
    +
    + + +
    +
    + + +
    +
    +
    Mimiz yt & be uhg im

    View Slide

  100. T
    CONCLUSION

    View Slide

  101. Sp kg  
    View v ly

    View Slide

  102. DRAWABLES ARE
    light-weig

    View Slide

  103. DRAWABLES ARE
    system-cacd

    View Slide

  104. DRAWABLES ARE
    cfig-pdt

    View Slide

  105. DRAWABLES ARE
    sy  use

    View Slide

  106. DRAWABLES ARE
    sy awome :)

    View Slide

  107. CYRIL MOTTIER
    @cyrilmoi
    cyrilmoi.com

    View Slide