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 full-size slide

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

    View full-size slide

  3. @cyrilmottier
    cyrilmottier.com

    View full-size slide

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

    View full-size slide

  5. An troduc 
    ANDROID DRAWABLES?

    View full-size slide

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


    Canvas

    View full-size slide

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

    View full-size slide

  8. getIntrinsicWidth()
    getIntrinsicHeight()

    View full-size slide

  9. setState(int[])

    View full-size slide

  10. setLevel(int)

    View full-size slide

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

    View full-size slide

  12. 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 full-size slide

  13.  from Java ...

    View full-size slide

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

    View full-size slide

  15. Tt’s a folks!

    View full-size slide

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

    View full-size slide

  17. T Drawab
    LOADING MECHANISM

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  21. Drawable
    BitmapDrawable ColorDrawable

    View full-size slide

  22. Drawable
    BitmapDrawable DrawableContainer
    ColorDrawable

    View full-size slide

  23. Drawable
    BitmapDrawable DrawableContainer
    ColorDrawable
    StateListDrawable LayerDrawable

    View full-size slide

  24. Drawable
    BitmapDrawable DrawableContainer
    ColorDrawable
    StateListDrawable LayerDrawable

    View full-size slide

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

    View full-size slide

  26. File ends
    with «.xml»

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  31. Let’s py!

    View full-size slide

  32. 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 full-size slide

  33. 03-23 16:39:29.745: DEBUG/Activity(19742): d1:
    android.graphics.drawable.BitmapDrawable@417e70c8
    03-23 16:39:29.745: DEBUG/Activity(19742): d2:
    android.graphics.drawable.BitmapDrawable@417e7130
    tputs

    View full-size slide

  34. 03-23 16:39:29.745: DEBUG/Activity(19742): d1:
    android.graphics.drawable.BitmapDrawable@417e70c8
    03-23 16:39:29.745: DEBUG/Activity(19742): d2:
    android.graphics.drawable.BitmapDrawable@417e7130
    tputs

    View full-size slide

  35. 03-23 16:39:29.745: DEBUG/Activity(19742): d1:
    android.graphics.drawable.BitmapDrawable@417e70c8
    03-23 16:39:29.745: DEBUG/Activity(19742): d2:
    android.graphics.drawable.BitmapDrawable@417e7130
    tputs

    View full-size slide

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

    View full-size slide

  37. 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 full-size slide

  38. 03-23 16:42:51.345: DEBUG/Activity(19742): d1.cs:
    android.graphics.drawable.BitmapDrawable$BitmapState@418078a8
    03-23 16:42:51.345: DEBUG/Activity(19742): d2.cs:
    android.graphics.drawable.BitmapDrawable$BitmapState@418078a8
    tputs

    View full-size slide

  39. 03-23 16:42:51.345: DEBUG/Activity(19742): d1.cs:
    android.graphics.drawable.BitmapDrawable$BitmapState@418078a8
    03-23 16:42:51.345: DEBUG/Activity(19742): d2.cs:
    android.graphics.drawable.BitmapDrawable$BitmapState@418078a8
    tputs

    View full-size slide

  40. 03-23 16:42:51.345: DEBUG/Activity(19742): d1.cs:
    android.graphics.drawable.BitmapDrawable$BitmapState@418078a8
    03-23 16:42:51.345: DEBUG/Activity(19742): d2.cs:
    android.graphics.drawable.BitmapDrawable$BitmapState@418078a8
    tputs

    View full-size slide

  41. Drawables
    ConstantState
    s ir

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  44. Some
    NICE GOTCHAS

    View full-size slide

  45. StateListDrawable












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

    View full-size slide

  46. StateListDrawable












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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  53. 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 full-size slide

  54. 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 full-size slide

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

    View full-size slide

  56. 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 full-size slide

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

    View full-size slide

  58. Advc
    DRAWABLE USAGE

    View full-size slide

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

    View full-size slide

  60. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  63. Drawable.Callback
    T sw:

    View full-size slide

  64. 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 full-size slide

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

    View full-size slide

  66. verifyDrawable(Drawable)
    Just use

    View full-size slide

  67. 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 full-size slide

  68. 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 full-size slide

  69. 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 full-size slide

  70. Fg
    VIEW HIERARCHY

    View full-size slide

  71. disclaimer: this is an imaginary screen

    View full-size slide

  72. 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 full-size slide

  73. 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 full-size slide

  74. 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 full-size slide

  75. 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 full-size slide

  76. 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 full-size slide

  77. disclaimer: this is an imaginary screen

    View full-size slide

  78. disclaimer: this is an imaginary screen

    View full-size slide

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

    View full-size slide

  80. 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 full-size slide

  81. 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 full-size slide

  82. 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 full-size slide

  83. 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 full-size slide

  84. disclaimer: this is an imaginary screen

    View full-size slide

  85. disclaimer: this is an imaginary screen

    View full-size slide

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

    View full-size slide

  87. T
    CONCLUSION

    View full-size slide

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

    View full-size slide

  89. DRAWABLES ARE
    light-weig

    View full-size slide

  90. DRAWABLES ARE
    system-cacd

    View full-size slide

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

    View full-size slide

  92. DRAWABLES ARE
    sy  use

    View full-size slide

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

    View full-size slide

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

    View full-size slide