Android Drawable, which is unknown for Efficient Usage

Source: Internet
Author: User

Android Drawable, which is unknown for Efficient Usage
1. Overview

Drawable is basically used in our usual development and is very useful to everyone. So what is Drawable? A thing that can be drawn on a canvas. Compared with a View, you do not need to consider measure and layout. You only need to consider how to draw a drawing (canavs ). Of course, there are certainly no strangers to the traditional usage of Drawable. Today we will mainly introduce the following usage of Drawable:

1. Custom Drawable. Compared with View, Drawable is lightweight and easy to use. In the future, you can change the idea of View first and try Drawable first.

2. I believe everyone is familiar with State Drawable, but have you ever tried to customize a State?

3. Use Drawable to improve our UI Perfermance and how to use Drawable to improve our UI performance.

 

2. Basic concepts of Drawable

In general, in addition to directly using images placed under Drawable, the actual usage of Drawable is related to xml. We can use labels such as shape and layer-list to draw background information, you can also use the selector label to define the effect of the View status. Of course, each tag corresponds to a real object class. The relationship is as follows: (picture from: Cyril Mottier: master_android_drawables)

Common usage here is not an example. The focus of this article is as follows.

2. Custom Drawable

For custom Drawable, you can write a class and inherit from the Drawable, similar to the custom View. Of course, there is only one core method for custom Drawable, that is, draw. So what is the actual function of custom Drawable? What can we do?

I believe that everyone is familiar with rounded corners and circular images. I have written about the implementation of custom views. For details, refer:

AndroidBitmapShader implements circular and rounded image

Android Xfermode implements circular and rounded image

Today, I want to tell you that custom views are also implemented without the need for custom Drawable, Which is simpler, more efficient, and more widely used (you can be the background of any View ).

1. RoundImageDrawable

The code is relatively simple. Let's take a look at RoundImageDrawable.

 

[Java]View plaincopy
  1. Packagecom. zhy. view;
  2.  
  3. Importandroid. graphics. Bitmap;
  4. Importandroid. graphics. BitmapShader;
  5. Importandroid. graphics. Canvas;
  6. Importandroid. graphics. ColorFilter;
  7. Importandroid. graphics. Paint;
  8. Importandroid. graphics. PixelFormat;
  9. Importandroid. graphics. RectF;
  10. Importandroid. graphics. Shader. TileMode;
  11. Importandroid. graphics. drawable. Drawable;
  12.  
  13. PublicclassRoundImageDrawableextendsDrawable
  14. {
  15.  
  16. PrivatePaintmPaint;
  17. PrivateBitmapmBitmap;
  18.  
  19. PrivateRectFrectF;
  20.  
  21. PublicRoundImageDrawable (Bitmapbitmap)
  22. {
  23. MBitmap = bitmap;
  24. BitmapShaderbitmapShader = newBitmapShader (bitmap, TileMode. CLAMP,
  25. TileMode. CLAMP );
  26. MPaint = newPaint ();
  27. MPaint. setAntiAlias (true );
  28. MPaint. setShader (bitmapShader );
  29. }
  30.  
  31. @ Override
  32. PublicvoidsetBounds (intleft, inttop, intright, intbottom)
  33. {
  34. Super. setBounds (left, top, right, bottom );
  35. RectF = newRectF (left, top, right, bottom );
  36. }
  37.  
  38. @ Override
  39. Publicvoiddraw (Canvascanvas)
  40. {
  41. Canvas. drawRoundRect (rectF, 30,30, mPaint );
  42. }
  43.  
  44. @ Override
  45. PublicintgetIntrinsicWidth ()
  46. {
  47. ReturnmBitmap. getWidth ();
  48. }
  49.  
  50. @ Override
  51. PublicintgetIntrinsicHeight ()
  52. {
  53. ReturnmBitmap. getHeight ();
  54. }
  55.  
  56. @ Override
  57. PublicvoidsetAlpha (intalpha)
  58. {
  59. MPaint. setAlpha (alpha );
  60. }
  61.  
  62. @ Override
  63. PublicvoidsetColorFilter (ColorFiltercf)
  64. {
  65. MPaint. setColorFilter (cf );
  66. }
  67.  
  68. @ Override
  69. PublicintgetOpacity ()
  70. {
  71. ReturnPixelFormat. TRANSLUCENT;
  72. }
  73.  
  74. }

     

    The core code is draw, but we only need a line ~~~~ The setAlpha, setColorFilter, getOpacity, and draw methods must be implemented. However, except for draw, the other methods are simple. GetIntrinsicWidth and getIntrinsicHeight are mainly used to provide the following dimensions when the View uses wrap_content. The default value is-1, which is not what we want. SetBounds is used to set the drawn range.

    OK. This is how the rounded corner image is implemented. It's easy ~~

    Check the usage:

     

    [Java]View plaincopy
    1. Bitmapbitmap = BitmapFactory. decodeResource (getResources (),
    2. R. drawable. mv );
    3. ImageViewiv = (ImageView) findViewById (R. id. id_one );
    4. Iv. setImageDrawable (newRoundImageDrawable (bitmap ));
      OK. paste our image, two imageviews, and one TextView.

       

      As you can see, it is not only used for ImageView to achieve the rounded corner of the image, but also can be used as the background of any View. In the case of stretching in ImageView, configure ScaleType. If other views are used as the background, see: Android BitmapShader for circular and rounded images. Detailed enough.

      2. CircleImageDrawable

      Next, let's look at the writing method of the custom circular Drawable:

       

      [Java]View plaincopy
      1. Packagecom. zhy. view;
      2.  
      3. Importandroid. graphics. Bitmap;
      4. Importandroid. graphics. BitmapShader;
      5. Importandroid. graphics. Canvas;
      6. Importandroid. graphics. ColorFilter;
      7. Importandroid. graphics. Paint;
      8. Importandroid. graphics. PixelFormat;
      9. Importandroid. graphics. RectF;
      10. Importandroid. graphics. Shader. TileMode;
      11. Importandroid. graphics. drawable. Drawable;
      12.  
      13. PublicclassCircleImageDrawableextendsDrawable
      14. {
      15.  
      16. PrivatePaintmPaint;
      17. PrivateintmWidth;
      18. PrivateBitmapmBitmap;
      19.  
      20. PublicCircleImageDrawable (Bitmapbitmap)
      21. {
      22. MBitmap = bitmap;
      23. BitmapShaderbitmapShader = newBitmapShader (bitmap, TileMode. CLAMP,
      24. TileMode. CLAMP );
      25. MPaint = newPaint ();
      26. MPaint. setAntiAlias (true );
      27. MPaint. setShader (bitmapShader );
      28. MWidth = Math. min (mBitmap. getWidth (), mBitmap. getHeight ());
      29. }
      30.  
      31. @ Override
      32. Publicvoiddraw (Canvascanvas)
      33. {
      34. Canvas. drawCircle (mWidth/2, mWidth/2, mWidth/2, mPaint );
      35. }
      36.  
      37. @ Override
      38. PublicintgetIntrinsicWidth ()
      39. {
      40. ReturnmWidth;
      41. }
      42.  
      43. @ Override
      44. PublicintgetIntrinsicHeight ()
      45. {
      46. ReturnmWidth;
      47. }
      48.  
      49. @ Override
      50. PublicvoidsetAlpha (intalpha)
      51. {
      52. MPaint. setAlpha (alpha );
      53. }
      54.  
      55. @ Override
      56. PublicvoidsetColorFilter (ColorFiltercf)
      57. {
      58. MPaint. setColorFilter (cf );
      59. }
      60.  
      61. @ Override
      62. PublicintgetOpacity ()
      63. {
      64. ReturnPixelFormat. TRANSLUCENT;
      65. }
      66.  
      67. }
        This is surprisingly simple. Let's take a look at it again:

         

        OK. For the custom Drawable example, over ~~~ Next we will look at the custom status.

        For more information, see Romain Guy's Blog.

        3. Customize the Drawable State

        I believe everyone is familiar with Drawable State and state_pressed.

        Next, we have a requirement, similar to the mailbox, that the mail is displayed in ListView form, but we need a status to identify unread and read: so, And We customize a status state_message_readed.

        :

        As you can see, if it is a read email, our icon is open and has a light red background. So how can we implement it through a custom drawable state?

        The custom drawable state can be divided into the following steps:

        1. res/values/create an xml file: drawable_status.xml

         

        [Html]View plaincopy
        1.  
        2.  
        3.  
        4.  
        5.  
        6.  

           

           

          2. inherit the container of Item

          Here we select the RelativeLayout implementation for Item, and we need to inherit it, And then rewrite its onCreateDrawableState method to add our custom state when appropriate.

           

          [Java]View plaincopy
          1. Packagecom. zhy. view;
          2.  
          3. Importcom. zhy. sample. drawable. R;
          4.  
          5. Importandroid. content. Context;
          6. Importandroid. util. AttributeSet;
          7. Importandroid. widget. RelativeLayout;
          8.  
          9. PublicclassMessageListItemextendsRelativeLayout
          10. {
          11.  
          12. Privatestaticfinalint [] STATE_MESSAGE_READED = {R. attr. state_message_readed };
          13. PrivatebooleanmMessgeReaded = false;
          14.  
          15. PublicMessageListItem (Contextcontext, AttributeSetattrs)
          16. {
          17. Super (context, attrs );
          18. }
          19.  
          20. PublicvoidsetMessageReaded (booleanreaded)
          21. {
          22. If (this. mMessgeReaded! = Readed)
          23. {
          24. MMessgeReaded = readed;
          25. RefreshDrawableState ();
          26. }
          27. }
          28.  
          29. @ Override
          30. Protectedint [] onCreateDrawableState (intextraSpace)
          31. {
          32. If (mMessgeReaded)
          33. {
          34. Finalint [] drawableState = super
          35. . OnCreateDrawableState (extraSpace + 1 );
          36. MergeDrawableStates (drawableState, STATE_MESSAGE_READED );
          37. ReturndrawableState;
          38. }
          39. Returnsuper. onCreateDrawableState (extraSpace );
          40. }
          41.  
          42. }
            The code is not complex. It declares a STATE_MESSAGE_READED and adds the custom state through the onCreateDrawableState method when mMessgeReaded = true.

             

            For similar code, you can look at the source code of CompoundButton (CheckBox parent class). It has a checked status:

             

            [Java]View plaincopy
            1. @ Override
            2. Protectedint [] onCreateDrawableState (intextraSpace ){
            3. Finalint [] drawableState = super. onCreateDrawableState (extraSpace + 1 );
            4. If (isChecked ()){
            5. MergeDrawableStates (drawableState, CHECKED_STATE_SET );
            6. }
            7. ReturndrawableState;
            8. }
              3. Use

               

              Layout file:

               

              [Html]View plaincopy
              1. Xmlns: tools = "http://schemas.android.com/tools"
              2. Android: layout_width = "match_parent"
              3. Android: layout_height = "50dp"
              4. Android: background = "@ drawable/message_item_bg">
              5.  
              6. Android: id = "@ + id/id_msg_item_icon"
              7. Android: layout_width = "30dp"
              8. Android: src = "@ drawable/message_item_icon_bg"
              9. Android: layout_height = "wrap_content"
              10. Android: duplicateParentState = "true"
              11. Android: layout_alignParentLeft = "true"
              12. Android: layout_centerVertical = "true"
              13. />
              14.  
              15. Android: id = "@ + id/id_msg_item_text"
              16. Android: layout_width = "match_parent"
              17. Android: layout_height = "wrap_content"
              18. Android: layout_centerVertical = "true"
              19. Android: layout_toRightOf = "@ id/id_msg_item_icon"/>
              20.  
              21.  
                Simple: an icon and text;

                 

                Activity

                 

                [Java]View plaincopy
                1. Packagecom. zhy. sample. drawable;
                2.  
                3. Importcom. zhy. view. MessageListItem;
                4.  
                5. Importandroid. app. ListActivity;
                6. Importandroid. OS. Bundle;
                7. Importandroid. view. LayoutInflater;
                8. Importandroid. view. View;
                9. Importandroid. view. ViewGroup;
                10. Importandroid. widget. ArrayAdapter;
                11. Importandroid. widget. TextView;
                12.  
                13. PublicclassCustomStateActivityextendsListActivity
                14. {
                15. PrivateMessage [] messages = newMessage [] {
                16. NewMessage ("Gasbilloverdue", true ),
                17. NewMessage ("Congratulations, you 'vewon! ", True ),
                18. NewMessage ("Iloveyou! ", False ),
                19. NewMessage ("Pleasereply! ", False ),
                20. NewMessage ("Youignoringme? ", False ),
                21. NewMessage ("Notheardfromyou", false ),
                22. NewMessage ("maid", true ),
                23. NewMessage ("Gasbill", true), newMessage ("Holidayplans", false ),
                24. NewMessage ("Marketingstuff", false ),};
                25.  
                26. @ Override
                27. ProtectedvoidonCreate (BundlesavedInstanceState)
                28. {
                29. Super. onCreate (savedInstanceState );
                30.  
                31. GetListView (). setAdapter (newArrayAdapter (This,-1, messages)
                32. {
                33. PrivateLayoutInflatermInflater = LayoutInflater
                34. . From (getContext ());
                35.  
                36. @ Override
                37. PublicViewgetView (intposition, ViewconvertView, ViewGroupparent)
                38. {
                39. If (convertView = null)
                40. {
                41. ConvertView = mInflater. inflate (R. layout. item_msg_list,
                42. Parent, false );
                43. }
                44. MessageListItemmessageListItem = (MessageListItem) convertView;
                45. TextViewtv = (TextView) convertView
                46. . FindViewById (R. id. id_msg_item_text );
                47. TV. setText (getItem (position). message );
                48. MessageListItem. setMessageReaded (getItem (position). readed );
                49. ReturnconvertView;
                50. }
                51.  
                52. });
                53.  
                54. }
                55. }
                  The code is very simple, but we can see that we need to call the setMessageReaded method in getView. Of course, some other States must also be manually triggered, such as triggering pressed in ACTION_DOWN. Do not worry about not using ViewHolder or anything. Just add it yourself.

                   

                  4. Improve Our UI Perfermance

                  Now we are paying more and more attention to performance issues. In fact, we don't need to care so much, but now that everyone cares, here we use Cyril Mottier: an example in master_android_drawables ppt shows how to use Drawable to improve the UI performance.

                  We can see this:

                  Layout file:

                   

                  [Html]View plaincopy
                  1.  
                  2. Android: layout_width = "match_parent"
                  3. Android: layout_height = "match_parent"
                  4. Android: background = "@ color/app_background"
                  5. Android: padding = "8dp">
                  6.  
                  7. Android: layout_width = "wrap_content"
                  8. Android: layout_height = "wrap_content"
                  9. Android: layout_gravity = "center"
                  10. Android: layout_marginBottom = "24dp"
                  11. Android: src = "@ drawable/logo"/>
                  12.  
                  13. Android: layout_width = "match_parent"
                  14. Android: layout_height = "48dp"
                  15. Android: layout_gravity = "bottom"
                  16. Android: orientation = "horizontal">
                  17.  
                  18. Android: layout_width = "0dp"
                  19. Android: layout_height = "fill_parent"
                  20. Android: layout_weight = "1"
                  21. Android: text = "@ string/sign_up"/>
                  22.  
                  23. Android: layout_width = "0dp"
                  24. Android: layout_height = "fill_parent"
                  25. Android: layout_weight = "1"
                  26. Android: text = "@ string/sign_in"/>
                  27.  
                  28.  
                  29.  
                    We can see that the outermost layer is FrameLayout, just to set the background image and padding. This layout is believed to have been written by many people.

                     

                    Let's take a look at the intuitive effect of this layout when the APP is started:

                    The user first sees a whiteboard and then shows our page. Next, we will use Drawable to improve our UI performance and user experience.

                    1. First, we remove the FrameLayout Of Our outermost layer, and then customize a drawable xml, called logo. xml.

                     

                    [Html]View plaincopy
                    1.  
                    2.  
                    3.  
                    4.  
                    5.  
                    6.  
                    7.  
                  30.  
                  31.  
                  32. Android: gravity = "center"
                  33. Android: src = "@ drawable/logo"/>
                  34.  
                  35.  
                    OK. This drawable sets our background and logo;

                     

                    2. Use it as the windowBackground of our current Activity

                     

                    [Html]View plaincopy
                    1.  
                    2. Name = "Theme. Default. NoActionBar"
                    3. Parent = "@ android: style/Theme. Holo. Light. NoActionBar">
                    4. @ Drawable/login
                    5.  
                    6.  
                  36.  

                     

                    3. Set it to Activity:

                     

                    [Html]View plaincopy
                    1. Android: name = "LoginActivity"
                    2. Android: theme = "@ style/Theme. Default. NoActionBar">
                      Okay, this not only minimizes our layout, but now there is only one LinearLayout and two buttons in our layout, and enhances the user experience. Now, when the user's visual effect is:

                       

                      Is it a good experience? I personally like this example ~~

                       

                      OK. Now our article is over ~~~ For most of the content, refer to examples written by some cool people. The example is great. You can also explore some things while reading this article ~~

                       

                       

                      Download source code

                       

                  Related Article

                  Contact Us

                  The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

                  If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

                  A Free Trial That Lets You Build Big!

                  Start building with 50+ products and up to 12 months usage for Elastic Compute Service

                  • Sales Support

                    1 on 1 presale consultation

                  • After-Sales Support

                    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

                  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.