自定義清理動畫

先上圖:
image

再附上:源碼地址
歡迎大家star~

上面的自定義動畫效果,有以下三個關鍵點:
1,背景顏色變化;
2,中心位置風車的旋轉;
3,四周小圈圈,吸收進中心位置;
下面詳細介紹它們實現方式:

實際整體控制動畫的流暢性,是利用屬性動畫輔助的:

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

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

    // 背景色漸變
    // ...省略代碼

    // 風扇 旋轉
    // ...省略代碼

    // 衝擊的 圈圈
    // ...省略代碼

    // 底部文案
    // ...省略代碼
}

利用屬性動畫,在 onAnimationUpdate 監聽裏面,invalidate 重走 onDraw 重繪;

背景色變化
mAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float progress = animation.getAnimatedFraction();
        // ...省略代碼
        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;

    // 背景色
    canvas.drawColor(mBgColor);
    // 背景色上蓋一層 漸變
    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);

    // 風扇 旋轉
    // ...省略代碼

    // 衝擊的 圈圈
    // ...省略代碼

    // 底部文案
    // ...省略代碼
}
風車旋轉
// ...省略代碼
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();
        // ...省略代碼
        // 每次旋轉15度
        mScanAngle += 15;

        invalidate();
    }
});

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

    // 背景色
    // ...省略代碼

    // 風扇 旋轉
    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;
        // 把風車圖片移到中心
        mBmMatrix.setTranslate(centerX - centerBmX, centerY - centerBmY);
        // 以圖片中心,旋轉角度
        mBmMatrix.preRotate(scanAngle, centerBmX, centerBmY);
        canvas.drawBitmap(mScanBitmap, mBmMatrix, mPaint);
    }

    // 衝擊的 圈圈
    // ...省略代碼

    // 底部文案
    // ...省略代碼
}
衝擊的圈圈
// 隨機生成某個方向的 圈圈
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;
}
/**
 * 添加新的一組圈圈,到屏幕裏;
 * mCurrentNextTime 會逐漸變大的,每間隔 NEXT_NEW_TIME 的時間,會增加一組圈圈,顯得看着連貫衝擊感;
 */
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;

    // 背景色
    // ...省略代碼

    // 風扇 旋轉
    // ...省略代碼

    // 衝擊的 圈圈
    Iterator<ScoreAnimationView.Circle> it = mCircles.iterator();
    while (it.hasNext()) {
        ScoreAnimationView.Circle circle = it.next();
        // 每個圈圈都有自己的進度,大於1了,就可以回收刪除了;
        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;

    // 底部文案
    // ...省略代碼
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章