Animation Implementation of Android Custom View

Posted by Tbull on Fri, 24 May 2019 01:07:05 +0200

Recently, we need to implement a histogram in our project and have an animation when we refresh the histogram (the histogram is dynamically drawn).
The common way to realize the histogram is to inherit View class, copy onDraw() method, draw the corresponding rectangle (drawRect method) and text (drawText method) in onDraw() method according to the needs of the product. The difficulty of realizing the histogram is to calculate the position of each column according to the actual business needs.
Following is a detailed description of the implementation of customized View animation. The author experimented with two methods in the implementation of bar animation:
1. The first method is to call invalidate() method by delaying a fixed time in drawing method, and then continue drawing View to achieve animation effect. The code is as follows:

    private int mIndex = 0;
    private void drawBar(Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL);

        for (BarItemInfoBean tempBarPosition : mBarInfoList) {


            PointF upperLeftPoint = tempBarPosition.getUpperLeftPoint();
            PointF lowerRightPoint = tempBarPosition.getLowerRightPoint();

            float left = upperLeftPoint.x;
            float top = upperLeftPoint.y;
            float right = lowerRightPoint.x;
            float bottom = lowerRightPoint.y;

            float delta = (lowerRightPoint.y - upperLeftPoint.y) / 10;          
            top = Math.max(lowerRightPoint.y - (mIndex + 1) * delta, upperLeftPoint.y);

            canvas.drawRect(left, top, right, bottom, mPaint);
        }

        mIndex++;

        if (mIndex < 10) { //Realizing animation effect by 10 delayed rendering
            postDelayed(new Runnable() {
                @Override
                public void run() {
                    invalidate();
                }
            }, 30);
        }
    }

2. The second method realizes animation effect through attribute animation.
Firstly, we customize an animation class to create a variable of animation property (mPhaseY) in the class, and we must set the get and set functions for this variable to use this property when creating ObjectAnimator objects.

public class ChartAnimator {

    private ValueAnimator.AnimatorUpdateListener mListener;

    public ChartAnimator() {

    }

    public ChartAnimator(ValueAnimator.AnimatorUpdateListener listener) {
        mListener = listener;
    }

    protected float mPhaseY = 1f;

    public void animateY(int durationMillis) {

        if (android.os.Build.VERSION.SDK_INT < 11)
            return;

        ObjectAnimator animatorY = ObjectAnimator.ofFloat(this, "phaseY", 0f, 1f);
        animatorY.setDuration(durationMillis);
        animatorY.addUpdateListener(mListener);
        animatorY.start();
    }

    public float getPhaseY() {
        return mPhaseY;
    }

    public void setPhaseY(float phase) {
        mPhaseY = phase;
    }

}

Then a ChartAnimator object is instantiated in a custom bar graph. When drawing a column in the onDraw() method, the height of the column depends on the return value of the animation attribute (mPhaseY) in the ChartAnimator object.

    private ChartAnimator mAnimator = new ChartAnimator();  
    private void drawBar(Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL);

        float phaseY = mAnimator.getPhaseY();

        for (BarItemInfoBean tempBarPosition : mBarInfoList) {


            PointF upperLeftPoint = tempBarPosition.getUpperLeftPoint();
            PointF lowerRightPoint = tempBarPosition.getLowerRightPoint();

            float left = upperLeftPoint.x;
            float top = upperLeftPoint.y;
            float right = lowerRightPoint.x;
            float bottom = lowerRightPoint.y;

            top = lowerRightPoint.y - (lowerRightPoint.y - upperLeftPoint.y) * phaseY;

            canvas.drawRect(left, top, right, bottom, mPaint);
        }
    }


    public void animateY(int durationMillis) {
        mAnimator.animateY(durationMillis);
    }

Comparing the two methods:
The first method is simple to implement and can be implemented on sdk under Android 3.0, but the animation effect is not as good as the second method.
The second method, which is more complex to implement, can only be used on sdk over Android 3.0. Its advantage is that it can control the animation effect (such as animation duration, acceleration, deceleration, etc.) well, and it is easy to expand.

Topics: Android Attribute SDK