StateBackgroundUtil - Use only one resource image to set a background with a pressed effect for View

StateBackgroundUtil - Use only one resource image to set a background with a pressed effect for View

This article mainly introduces how to use a resource image to set a background drawable with a pressed effect for View.

origin

Some time ago, when developing a new version of the project, the designer came up with a set of specifications for the project's press effects. The specifications are roughly like this.

For general buttons, there are only two different implementations of the button press effect.

1. Press this to darken the background image. Specifically, add a 20% black mask on the normal drawable.

2. After pressing, reduce the transparency of the front background resource. Specifically, change the transparency of the normal state drawable to 70% of the original when pressed.

Obviously, this set of specifications will bring the following benefits.

  • When producing a picture, the designer only needs to produce one picture, and then only needs to tell the developer the corresponding pressing effect strategy, which can reduce the designer's burden of producing pictures.
  • The same is true for the client side. There is no need to import two resource images to achieve a press effect. This reduces the package size and also saves the client developer the trouble of writing selector files.

Implementation

In fact, I had this thought before during the development process, wondering how to set the background of a View based on a picture and make it have a pressed effect. At first, I naturally thought of handling the touch event of the View, and then dynamically setting the background resource after pressing according to the normal background when pressing.

But later I found it was still troublesome, and sometimes some Views themselves needed to handle touch events, which would cause conflicts, so I just gave up at that time.

After some searching and thinking, I finally used StateListDrawable to achieve the desired effect.

StateListDrawable has a method addState that is used to set the drawable in different states, including pressed, focused, unavailable, and all other states.

Therefore, combined with the needs, here we only need to calculate the drawable of the pressed state based on the drawable in the normal state, and then set it to the pressed state, and we can realize a set of resources to realize the pressed state of View.

Specific implementation

The solution has been explained clearly, and the implementation is actually very simple. The code is as follows.

  1. private static Drawable getBackground(@NonNull Context context, @DrawableRes int res, @StatePressedMode.Mode int mode, @FloatRange( from = 0.0f, to = 1.0f) float alpha) {
  2. Drawable normal = context.getResources().getDrawable(res);
  3. Drawable pressed = context.getResources().getDrawable(res);
  4. pressed.mutate(); //Set different pressed drawables according to different pressing requirements
  5. setPressedStateDrawable(mode, alpha, pressed); final StateListDrawable stateListDrawable = new StateListDrawable(); //Pressed state
  6. stateListDrawable.addState(new int []{android.R.attr.state_pressed}, pressed); //Normal state
  7. stateListDrawable.addState(new int []{}, normal); return stateListDrawable;
  8. }

Process the pressed drawable according to different pressing modes

  1. private static void setPressedStateDrawable(@StatePressedMode.Mode int mode, @FloatRange( from = 0.0f, to = 1.0f) float alpha, @NonNull Drawable pressed) { switch (mode) { case StatePressedMode.ALPHA:
  2. pressed.setAlpha(convertAlphaToInt(alpha)); break; case StatePressedMode.DARK:
  3. pressed.setColorFilter(alphaColor(Color.BLACK, convertAlphaToInt(alpha)), PorterDuff.Mode.SRC_ATOP); break; default :
  4. pressed.setAlpha(convertAlphaToInt(alpha));
  5. }
  6. }

The implementation of this solution has been placed on GitHub, StateBackgroundUtil . You are welcome to observe and support it.

Some details

When setting the pressed state drawable,

  1. Drawable normal = context.getResources().getDrawable(res);
  2. Drawable pressed = context.getResources().getDrawable(res);

The resource res used by normal and pressed here has the same id. However, during the drawable loading process, if the same res resource is loaded into the memory once, the state corresponding to the drawable will remain consistent, so pressed needs to be set variable here.

  1. pressed.mutate();

Official description of the mutate method

This is especially useful when you need to modify properties of drawables loaded from resources. By default, all drawables instances loaded from the same resource share a common state;

Note: Since the pressing effect of View can only be seen when clickable is set to true, you should know what to do if you use StateBackgroundUtil to set the background for View but find that there is no pressing effect.

insufficient

  • Unclickable state is not currently supported
  • Does not support color background (of course you can use shape curves to save the country)

***, if you find any problems, please point them out in the issue or comment area, and you are also welcome to PR a better solution.

<<:  Gradle for Android Part 4 (Build Variants)

>>:  Tremble, humans! After AlphaGo, there is the Cold Poker Master

Recommend

APP promotion, how can a single APP reach tens of millions of downloads?

First of all, application promotion should mainly...

Apple's atypical innovation: making money from user loyalty

The industry knows that Apple has always used so-...

The “4-word secret” for event operation planning!

In the actual work of operation planning, we may ...

How to buy traffic and acquire users on Douyin at low cost?

Tik Tok is still in its wild growth period, with ...

What will humans wear when they arrive on Mars?

For a long time, humans have been full of curiosi...

How much does it cost to join a dance school mini program in Qiandongnan?

How much does it cost to join Qiandongnan Dance S...

New evidence of extraterrestrial life was discovered on this planet!

A team led by scientists from the Southwest Resea...