concept

Drawable refers to an abstract concept that can be drawn on Canvas. There are many kinds of Drawable, such as colors and pictures.

advantages

  1. First, it is relatively easy to use, in XML has defined a large number of attribute methods, as long as we are familiar with the UI effects and characteristics of each attribute can be combined with various interface effects.
  2. Secondly, its implementation cost is lower than that of a custom View. Drawable will reduce the development cost for some simple, customized and repetitive UI effects. However, for more complex UI scenarios, Drawable does not behave like a custom view.
  3. Compared with pictures, drawable takes up less space, which is conducive to reducing the size of APK.

form

Drawable although not usually visible to applications, Drawable can take many forms:

Bitmap: The simplest Drawable, a PNG or JPEG image.

Nine Patch: Is an extension to the PNG format that allows it to specify how to stretch and place it

A drawable set of points, lines, and curves and associated color information defined in an XML file. This type of drawing can be scaled without loss of display quality.

Shape: Contains simple drawing commands instead of raw bitmaps, allowing for better adjustments in some cases.

A drawable compound that draws Layers on top of each other.

States: a composite drawable that selects one of a set of drawables based on its state.

A composite drawable, selected from a set of drawables based on its Levels.

A drawable combination whose overall size is modified according to the current level.

Direct and indirect subclasses

XML parsing process

The final inflateFromTag method

@NonNull @SuppressWarnings("deprecation") private Drawable inflateFromTag(@NonNull String name) { switch (name) { case "selector": return new StateListDrawable(); case "animated-selector": return new AnimatedStateListDrawable(); case "level-list": return new LevelListDrawable(); case "layer-list": return new LayerDrawable(); case "transition": return new TransitionDrawable(); case "ripple": return new RippleDrawable(); case "adaptive-icon": return new AdaptiveIconDrawable(); case "color": return new ColorDrawable(); case "shape": return new GradientDrawable(); case "vector": return new VectorDrawable(); case "animated-vector": return new AnimatedVectorDrawable(); case "scale": return new ScaleDrawable(); case "clip": return new ClipDrawable(); case "rotate": return new RotateDrawable(); case "animated-rotate": return new AnimatedRotateDrawable(); case "animation-list": return new AnimationDrawable(); case "inset": return new InsetDrawable(); case "bitmap": return new BitmapDrawable(); case "nine-patch": return new NinePatchDrawable(); case "animated-image": return new AnimatedImageDrawable(); default: return null; }}Copy the code

The real case

shape count radio
shape 833 73%
selector 240 21%
layer-list 50
animated-rotate 7
animation-list 5
vector 3
rotate 2
level-list 1

In my project, the total number of drawable files is 1140, of which shape is the largest with 833, accounting for 73%, followed by selector with 240, accounting for 21%, and the two together account for 94%. The difference between these two types is very small, mainly due to the difference in background color and rounded Angle, resulting in a large number of files. Moreover, it is difficult to unify the name of such files, which makes it difficult to achieve the effect of reuse. Sometimes, it is far faster to find a target file than to create a new Drawable file. This is gradually leading to an explosion of such files. Thus increasing the volume of APK.


You can see through the XML parsing process, the XML just comes out with a specific tag that corresponds to the class, and then sets the specific parameters, so you can actually create the specific object and set the parameters, so you don’t have to do XML parsing,

A better way to do it — code

      mViewBinding.lineDrawable.background = shapeDrawable(this) {
            lineShape()
            dash(10, 5)
            strokeColor(Color.RED)
            strokeWidth(2)
        }
        
       
      mViewBinding.stateListDrawable.background = selectorDrawable {

          pressedDrawable {
                shapeDrawable(this@MainActivity) {
                    solidColor(Color.BLUE)
                    radius(8)
                }
          }

          defaultDrawable {
                shapeDrawable(this@MainActivity) {
                    solidColor(Color.GRAY)
                    radius(8)
                }
          }

      }

Copy the code

advice

Specific projects can be encapsulated once, reducing the creation of conditions each time, so that only need to pass specific parameters can be easy to reuse, of course, the project also encapsulated several general methods. Such as:

    fun shapeDrawableColorInt(context: Context, @ColorInt colorInt: Int = Color.WHITE, radius: Int = 0) =
        shapeDrawable(context) {
            solidColor(colorInt)
            radius(radius)
    }


    fun shapeDrawableColorRes(context: Context, @ColorRes colorRes: Int, radius: Int = 0) =
        shapeDrawable(context) {
            solidColorRes(colorRes)
            radius(radius)
    }

Copy the code

advantages

Improved performance over XML:

  1. Avoid the XML parsing process
  2. Reuse this code
  3. Easier to manage than XML

Reference way

Making the address

Implementation 'IO. Making. Weiggle: drawable: 1.0.1'Copy the code