1. Introduction

Recently, Hongyang And Lu Yao respectively published on their public account about the solution to solve the Shape/Selector redundancy. The article was written last weekend. Although there are many similar solutions, the implementation ideas are similar. But I still have to settle for my solution. There are several reasons.

  1. This is pure code that implements XML Drawable without rewriting the basic components of a custom View or Hook system.

  2. The ability to replicate XML as much as possible, even in terms of dp or PX apis.

  3. Using the Builder pattern to constrain methods and parameters makes it easy to use without having to find methods in numerous apis. Combined with Kotlin’s grammar, the word “fragrant”.

  4. There is an internal caching policy and a Hash weighting policy, which is also not available in other solutions on the market.

The catch, of course, is that currently all XML replacements need to be done manually, and it would be nice if the Gradle plug-in could automatically convert them at compile time. If you have the experience, try to make the library better together.

2. Why does Android use XML to generate Drawable

XML is the preferred way to generate GradientDrawable and SelectorDrawable on Android, so many students are used to generating GradientDrawable and SelectorDrawable using XML, and they’re really handy. But the ensuing problem, as I’m sure many of you will know, is that even a GradientDrawable change in the size of a rounded corner or a color value requires a new copy of the original XML file, leading to a growing number of drawable files in the project. Even teams with poor coding standards may have multiple drawable versions of exactly the same effect in their projects.

Is it necessary to deal with this situation? Most XML files are only 12 KB, taking up very little space and not affecting package size that much. Although Android’s Drawable cache is based on the file name dimension, its recycling strategy is pretty good. Redundant XML has an impact on memory footprint, but not that much.

So let the number of files swell? I think the answer is a matter of opinion, do not deal with it, nothing more than to write up a bloated point bai, at least do not take the time to think of a solution. Of course, we could be more refined and use a code-generated Drawable scheme to achieve exactly the same effect as XML, while avoiding redundant XML files.

Unexpected bonus 👉 when using SVG as an image in the project, I found that on Android5.0 and Android6.0 phones, the selector images defined by XML did not display properly. The reason is that Android7.0 does not support SVG fillType, resulting in the selector rendering problem. I thought about it a lot, but I couldn’t solve it, and I finally solved it by generating a selector solution in code.

Before we start writing Drawable generation in code, let’s ask ourselves a question. Okay? Why does Android prefer the XML Drawable scheme?

After analyzing the principles of XML rendering Drawable, I think system compatibility may be an important reason to use XML. Take the setPadding method GradientDrawable, introduced in the Android Q version. If we introduce padding in the XML file, we will not have a problem in versions below Android Q. If it is used in code, you need to do version judgment

<padding android:top="10dp" android:bottom="10dp" android:left="10dp" android:right="10dp"></padding>
Copy the code

Without further discussion, let’s take a look at the final effect, below, GradientDrawable generated from XML on the left and code on the right.

3. XML implementation and code implementation

Let’s look at the code implementation

  1. GradientDrawable XML implementation

2. GradientDrawable code implementation

  1. StateListDrawable XML implementation

4. StateListDrawable code implementation

The addState(StatePressed) method says Android :state_pressed=”true”

The minusState(StatePressed) method says Android :state_pressed=”false”

You can also add multiple states

4. Features and source code

The library has the following features:

  1. Anything XML can do, it can do
  2. Using Builder mode, it is easier to build Drawable
  3. Support for all Android :state_xxx
  4. GradientDrawable, so long as all GradientDrawable builds are the same (order can be scrambled), only one copy will remain in memory

Because part of the readers have not mastered the science of the Internet, the source code on their own public number, the amount of code is not much, it can be used. Source address 👉 source address