Custom cleanup animation

First of all:

Attached: Source address
Welcome, star~

The above custom animation effect has the following three keys:
1. Background color change;
2. Rotation of windmill at the center;
3. Small circle around and absorbed into the center;
The following details how they are implemented:

The actual overall control of animation fluency is assisted by attribute Animation:

mAnim = ValueAnimator.ofInt(0, 100);
mAnim.setDuration(30 * 1000);
mAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float progress = animation.getAnimatedFraction();
        // ... omit code
        invalidate();
    }
});

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int centerX = getWidth() / 2;
    int centerY = getHeight() / 2;

    // Background gradient
    // ... omit code

    // Fan rotation
    // ... omit code

    // The circle of impact
    // ... omit code

    // Bottom copy
    // ... omit code
}

Using attribute animation, in onAnimationUpdate monitor, invalidate and redraw onDraw;

Background color change
mAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float progress = animation.getAnimatedFraction();
        // ... omit code
        mCurrentScore = (int) ((mTargetScore - mCurrentScore) * progress + mCurrentScore);
        mBgColor = mArgbEvaluator.evaluate((float) mCurrentScore/100, CleanColorHelper.Colors.RED, CleanColorHelper.Colors.GREEN);

        invalidate();
    }
});

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int centerX = getWidth() / 2;
    int centerY = getHeight() / 2;

    // Background color
    canvas.drawColor(mBgColor);
    // Cover the background with a gradient
    if (mLGradient == null) {
        mLGradient = new LinearGradient(0, 0, getWidth(), getHeight(), 0x88ffffff, 0x00ffffff, Shader.TileMode.REPEAT);
    }
    mPaint.setShader(mLGradient);
    canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);

    // Fan rotation
    // ... omit code

    // The circle of impact
    // ... omit code

    // Bottom copy
    // ... omit code
}
Windmill rotation
// ... omit code
mScanBitmap = BitmapUtils.getBitmapFromResourceWithHighQuality(getContext().getResources(), R.drawable.manage_icon_scan_fs, 268, 268);
mAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float progress = animation.getAnimatedFraction();
        // ... omit code
        // 15 degrees per rotation
        mScanAngle += 15;

        invalidate();
    }
});

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int centerX = getWidth() / 2;
    int centerY = getHeight() / 2;

    // Background color
    // ... omit code

    // Fan rotation
    if (mScanBitmap != null) {
        mPaint.setShader(null);
        mPaint.setAlpha((int) (255));
        mPaint.setStyle(Paint.Style.FILL);
        float scanAngle = mScanAngle % 360;
        int centerBmX = mScanBitmap.getWidth() / 2;
        int centerBmY = mScanBitmap.getHeight() / 2;
        // Move windmill picture to center
        mBmMatrix.setTranslate(centerX - centerBmX, centerY - centerBmY);
        // Rotate in the center of the picture
        mBmMatrix.preRotate(scanAngle, centerBmX, centerBmY);
        canvas.drawBitmap(mScanBitmap, mBmMatrix, mPaint);
    }

    // The circle of impact
    // ... omit code

    // Bottom copy
    // ... omit code
}
The circle of impact
// Randomly generate a circle in a certain direction
private ScoreAnimationView.Circle obtainNewCircle(int where) {
    ScoreAnimationView.Circle circle = new ScoreAnimationView.Circle();
    circle.where = where;
    int random = DensityUtils.dip2px(-30f) + RandomUtils.getRandomInt(DensityUtils.dip2px(60f));
    if (where == 0) {
        circle.x = DensityUtils.dip2px(-100f) + random * 2;
        circle.y = DensityUtils.dip2px(-150f) + random;
        circle.radius = DensityUtils.dip2px(30f) + random / 6;
        circle.color = ScoreAnimationView.MC;
    } else if (where == 1) {
        circle.x = DensityUtils.dip2px(120f) + random;
        circle.y = DensityUtils.dip2px(-150f) + random / 2;
        circle.radius = DensityUtils.dip2px(25f) + random / 6;
        circle.color = ScoreAnimationView.MC;
    } else if (where == 2) {
        circle.x = DensityUtils.dip2px(-110f) + random;
        circle.y = DensityUtils.dip2px(150f) + random * 2;
        circle.radius = DensityUtils.dip2px(26f) + random / 6;
        circle.color = ScoreAnimationView.MC;
    } else if (where == 3) {
        circle.x = DensityUtils.dip2px(100f) + random / 2;
        circle.y = DensityUtils.dip2px(150f) + random;
        circle.radius = DensityUtils.dip2px(20f) + random / 6;
        circle.color = ScoreAnimationView.MC;
    } else if (where == 4) {
        circle.x = DensityUtils.dip2px(-200f) + random / 2;
        circle.y = DensityUtils.dip2px(10f) + random / 2;
        circle.radius = DensityUtils.dip2px(15f) + random / 6;
        circle.color = ScoreAnimationView.MC;
    } else if (where == 5) {
        circle.x = DensityUtils.dip2px(200f) + random / 2;
        circle.y = DensityUtils.dip2px(-10f) + random / 2;
        circle.radius = DensityUtils.dip2px(18f) + random / 6;
        circle.color = ScoreAnimationView.MC;
    }
    return circle;
}
/**
 * Add a new set of circles to the screen;
 * mCurrentNextTime It will gradually become larger. Each time interval between next ﹣ new ﹣ time, a group of circles will be added to show a sense of coherence and impact;
 */
private void addNewCircles() {
    if (mCurrentNextTime >= NEXT_NEW_TIME
            && mCurrentNextTime < NEXT_NEW_TIME + LOOP_TIME) {
        mCurrentNextTime = 0;
        mCircles.add(obtainNewCircle(0));
        mCircles.add(obtainNewCircle(1));
        mCircles.add(obtainNewCircle(2));
        mCircles.add(obtainNewCircle(3));
        mCircles.add(obtainNewCircle(4));
        mCircles.add(obtainNewCircle(5));
    }
}
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int centerX = getWidth() / 2;
    int centerY = getHeight() / 2;

    // Background color
    // ... omit code

    // Fan rotation
    // ... omit code

    // The circle of impact
    Iterator<ScoreAnimationView.Circle> it = mCircles.iterator();
    while (it.hasNext()) {
        ScoreAnimationView.Circle circle = it.next();
        // Each circle has its own progress. If it is greater than 1, it can be recycled and deleted;
        if (circle.progress > 1) {
            it.remove();
        } else {
            mPaint.setShader(null);
            mPaint.setColor(circle.color);
            mPaint.setAlpha((int) (125 * (1f - circle.progress)));
            float x = centerX + circle.x * (1f - circle.progress);
            float y = centerY + circle.y * (1f - circle.progress);
            float radius = circle.radius * (1.2f - circle.progress);
            canvas.drawCircle(x, y, radius, mPaint);
            circle.progress += LOOP_TIME;
        }
    }
    addNewCircles();
    mCurrentNextTime += LOOP_TIME;

    // Bottom copy
    // ... omit code
}

Tags: Attribute

Posted on Fri, 10 Jan 2020 07:37:09 -0800 by zyntrax