This is the 25th day of my participation in the August Genwen Challenge.More challenges in August

Series of articles

Android color gradient animation effect implementation


There is source code at the end of the article


preface

The example effect is easy to implement by using the Android color estimator ArgbEvaluator(), which is the focus of this article.

Effect:


TypeEvaluator in Android

TypeEvaluator is an interface that you can customize in development to use ValueAnimator’s setEvaluator(TypeEvaluator) method to control the updated evaluation expression of an animation. In everyday development, it is not possible to manipulate changes in a single value. If you need to manipulate multiple properties of an object simultaneously, such as defining x, y movement coordinates for an animation, etc., you will need to know something about TypeEvaluator.

2. Case effect realization

1. Use ArgbEvaluator, the color estimator that comes with Android

  ValueAnimator colorAnim = ObjectAnimator.ofInt(this."backgroundColor", RED, BLUE);
        colorAnim.setDuration(4000);
        colorAnim.setEvaluator(new ArgbEvaluator());
        colorAnim.setRepeatCount(ValueAnimator.INFINITE);
        colorAnim.setRepeatMode(ValueAnimator.REVERSE);
        colorAnim.start();
Copy the code

2. Look at the ArgbEvaluator core code that comes with Android

    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        int startInt = (Integer) startValue;
        float startA = ((startInt >> 24) & 0xff) / 255.0 f;
        float startR = ((startInt >> 16) & 0xff) / 255.0 f;
        float startG = ((startInt >>  8) & 0xff) / 255.0 f;
        float startB = ( startInt        & 0xff) / 255.0 f;

        int endInt = (Integer) endValue;
        float endA = ((endInt >> 24) & 0xff) / 255.0 f;
        float endR = ((endInt >> 16) & 0xff) / 255.0 f;
        float endG = ((endInt >>  8) & 0xff) / 255.0 f;
        float endB = ( endInt        & 0xff) / 255.0 f;

        // Convert sRGB to linear
        startR = (float) Math.pow(startR, 2.2);
        startG = (float) Math.pow(startG, 2.2);
        startB = (float) Math.pow(startB, 2.2);

        endR = (float) Math.pow(endR, 2.2);
        endG = (float) Math.pow(endG, 2.2);
        endB = (float) Math.pow(endB, 2.2);

        // Compute interpolating colors in linear space
        float a = startA + fraction * (endA - startA);
        float r = startR + fraction * (endR - startR);
        float g = startG + fraction * (endG - startG);
        float b = startB + fraction * (endB - startB);

        // Convert back to sRGB in the [0..255] range
        a = a * 255.0 f;
        r = (float) Math.pow(r, 1.0 / 2.2) * 255.0 f;
        g = (float) Math.pow(g, 1.0 / 2.2) * 255.0 f;
        b = (float) Math.pow(b, 1.0 / 2.2) * 255.0 f;

        return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
    }
Copy the code

3. Customize a color estimator based on the implementation of ArgbEvaluator

public class MyColorEvaluator implements TypeEvaluator
Copy the code

Next, I changed the calculation method of Color. In the process of reading relevant API, I found colorToHSV and HSVToColor methods in Color, so I found a calculation method of HVS on the Internet. (The following code comes from the network).

 @Override
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        Color.colorToHSV(startValue,startHsv);
        Color.colorToHSV(endValue,endHsv);
        int alpha = startValue >> 24 + (int) ((endValue >> 24 - startValue >> 24) * fraction);
        // Calculate the color value corresponding to the current animation completion (fraction)
        if (endHsv[0] - startHsv[0] > 180) {
            endHsv[0] - =360;
        } else if (endHsv[0] - startHsv[0] < -180) {
            endHsv[0] + =360;
        }
        outHsv[0] = startHsv[0] + (endHsv[0] - startHsv[0]) * fraction;
        if (outHsv[0] > 360) {
            outHsv[0] - =360;
        } else if (outHsv[0] < 0) {
            outHsv[0] + =360;
        }
        outHsv[1]=startHsv[1]+(endHsv[1]-startHsv[1])*fraction;
        outHsv[2]=startHsv[2]+(endHsv[2]-startHsv[2])*fraction;


        return Color.HSVToColor(alpha,outHsv);

    }
Copy the code

4. Use your own color interpolator MyColorEvaluator

 ValueAnimator colorAnim = ObjectAnimator.ofInt(this."backgroundColor", RED, BLUE);
        colorAnim.setDuration(4000);
        colorAnim.setEvaluator(new MyColorEvaluator());
        colorAnim.setRepeatCount(ValueAnimator.INFINITE);
        colorAnim.setRepeatMode(ValueAnimator.REVERSE);
        colorAnim.start();
Copy the code

Three, the source code

ColorGradient.java:

public class ColorGradient extends View {

    public ColorGradient(Context context) {
        super(context);
    }

    public ColorGradient(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        animation();
    }

    public ColorGradient(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    private void animation(a){
        ValueAnimator colorAnim = ObjectAnimator.ofInt(this."backgroundColor", RED, BLUE);
        colorAnim.setDuration(4000);
        colorAnim.setEvaluator(newMyColorEvaluator()); colorAnim.setRepeatCount(ValueAnimator.INFINITE); colorAnim.setRepeatMode(ValueAnimator.REVERSE); colorAnim.start(); }}Copy the code

MyColorEvaluator.java:

public class MyColorEvaluator implements TypeEvaluator<Integer> {
    float[] startHsv=new float[3].float[] endHsv=new float[3].float[] outHsv=new float[3];

    @Override
    public Integer evaluate(floatfraction, Integer startValue, Integer endValue) { Color.colorToHSV(startValue,startHsv); Color.colorToHSV(endValue,endHsv); int alpha = startValue >> 24 + (int) ((endValue >> 24 - startValue >> 24) * fraction); // Calculate the color value corresponding to the current animation completion (fraction)if (endHsv[0] - startHsv[0] > 180) {
            endHsv[0] -= 360;
        } else if (endHsv[0] - startHsv[0] < -180) {
            endHsv[0] += 360;
        }
        outHsv[0] = startHsv[0] + (endHsv[0] - startHsv[0]) * fraction;
        if (outHsv[0] > 360) {
            outHsv[0] -= 360;
        } else if (outHsv[0] < 0) {
            outHsv[0] += 360;
        }
        outHsv[1]=startHsv[1]+(endHsv[1]-startHsv[1])*fraction;
        outHsv[2]=startHsv[2]+(endHsv[2]-startHsv[2])*fraction;


        returnColor.HSVToColor(alpha,outHsv); }}Copy the code