自定义控件

[Android高级动画] 如何让点扩散再聚合?

2019-06-09  本文已影响23人  小米Metre
如何让多个点扩散再聚合?

like this:

效果图
一、如何绘制多个点为一个圆形

点击 如何让绘制多个点并按圆形旋转?

该篇主要讲,如何让点扩散再聚合

二、如何让多个点扩散再聚合呢?
1、原理分析:

该效果可分为两步:先将点扩散、再将点聚合在一起。
扩散:可以通过放大,点围成的圆的半径。
聚合:也是一样的,就是缩小点围成的圆的半径。

这里会使用到OvershootInterpolator插值器。该插值器,到一定值后,又会再回到原来位置。刚好可以实现聚合的效果。

2、具体实现:

定义属性动画

//mCircleRadius小球的半径
//mRadius小球围成的圆的半径
ValueAnimator mAnimator = ValueAnimator.ofFloat(mCircleRadius,mRadius);
mAnimator.setDuration(1000);
//OvershootInterpolator 向前甩一定值后再回到原来位置 
// (tension=20,影响扩大比例的值)
mAnimator.setInterpolator(new OvershootInterpolator(20f));
//mAnimator.setRepeatCount(2);//默认0,执行一次
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
          //扩散圆的半径的变化值
          mCurrentRadius = (float)animation.getAnimatedValue();
          invalidate();
        }
   });

//reverse()动画反向执行
mAnimator.reverse();

绘制小球:

private void drawBallState(Canvas canvas){
    double degrees = Math.PI * 2 / colors.length;

    for (int i = 0; i < colors.length; i++) {

        // x = r * cos(a) + centX;
        // y= r * sin(a) + centY;

        mPaint.setColor(colors[i]);
        float angle = (float) ((i * degrees) + mCurrentRotateDegrees);

        float cx = (float) (mCurrentRadius * Math.cos(angle) + mCenterX);
        float cy = (float) (mCurrentRadius * Math.sin(angle) + mCenterY);

        canvas.drawCircle(cx,cy,mCircleRadius,mPaint);
    }
}

以上就可以是实现,扩散再聚合效果啦!

最后附上完整代码:

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;

import androidx.annotation.Nullable;

public class CircleView extends View {
    public CircleView(Context context) {
        this(context,null);
    }

    public CircleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private Paint mPaint = new Paint();
    private int[] colors;

    //旋转圆的中心坐标
    private float mCenterX;
    private float mCenterY;


    //小球的半径
    private float mCircleRadius = 20;

    //小球围成的圆的半径
    private float mRadius  = 100;

    private float mCurrentRotateDegrees;
    private float mCurrentRadius = mRadius;


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenterX = w * 1f /2;
        mCenterY = h * 1f/2;
    }

    private void init(){
        mPaint.setStyle(Paint.Style.FILL);
        colors = getResources().getIntArray(R.array.color_array);

    }

    private BallState mBallState;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if(mBallState == null){
            mBallState = new RotateState();
        }

        mBallState.drawState(canvas);

    }

    class RotateState implements BallState{

        private RotateState(){
            ValueAnimator mAnimator = ValueAnimator.ofFloat(0,(float) Math.PI);
            mAnimator.setDuration(1000);
            //LinearInterpolator以常量速率改变
            mAnimator.setInterpolator(new LinearInterpolator());
            mAnimator.setRepeatCount(2);
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentRotateDegrees = (float)animation.getAnimatedValue();

                    invalidate();
                }
            });

            mAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    //旋转动画结束后,开始扩散聚合动画
                    mBallState = new MergeState();
                }
            });

            mAnimator.start();
        }

        @Override
        public void drawState(Canvas canvas) {
            drawBallState(canvas);
        }
    }

    class MergeState implements BallState{

        private MergeState(){
            ValueAnimator mAnimator = ValueAnimator.ofFloat(mCircleRadius,mRadius);
            mAnimator.setDuration(1000);
            //OvershootInterpolator 向前甩一定值后再回到原来位置 (tension影响扩大比例的值)
            mAnimator.setInterpolator(new OvershootInterpolator(20f));
            //mAnimator.setRepeatCount(2);//默认0,执行一次
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentRadius = (float)animation.getAnimatedValue();
                    Log.d("CircleView","onAnimationUpdate | mCurrentRadius-->"+mCurrentRadius);
                    invalidate();
                }
            });

            //mAnimator.start();
            //动画反向执行
            mAnimator.reverse();
        }


        @Override
        public void drawState(Canvas canvas) {
            drawBallState(canvas);
        }
    }

    interface BallState{
        void drawState(Canvas canvas);
    }

    private void drawBallState(Canvas canvas){
        double degrees = Math.PI * 2 / colors.length;

        for (int i = 0; i < colors.length; i++) {

            // x = r * cos(a) + centX;
            // y= r * sin(a) + centY;

            mPaint.setColor(colors[i]);

            float angle = (float) ((i * degrees) + mCurrentRotateDegrees);

            float cx = (float) (mCurrentRadius * Math.cos(angle) + mCenterX);
            float cy = (float) (mCurrentRadius * Math.sin(angle) + mCenterY);

            canvas.drawCircle(cx,cy,mCircleRadius,mPaint);
        }
    }
}

上一篇下一篇

猜你喜欢

热点阅读