Android 自定义两球旋转动画效果

自定义一个两球旋转动画效果,可以用于加载时的动画展示

Android 自定义两球旋转动画效果_第1张图片

先定义attrs属性

<resources>
    <declare-styleable name="BallRotationAnim">
        
        <attr name="max_radius" format="dimension" />
        
        <attr name="min_radius" format="dimension" />
        
        <attr name="one_color" format="color" />
        
        <attr name="two_color" format="color" />
        
        <attr name="distance" format="dimension" />
        
        <attr name="duration" format="integer" />
    declare-styleable>
resources>

具体步骤都在注释里

package com.example.twoballrotationanim.widget;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

import com.example.twoballrotationanim.R;

/**
 * 两个小球旋转动画
 */
public class BallRotationAnim extends View {
    //默认最大半径
    private final static int DEFUALT_MAX_RADIUS = 25;
    //默认最小半径
    private final static int DEFUALT_MIN_RADIUS = 15;
    //默认两个球心距离
    private final static int DEFAULT_DISTANCE = 35;
    //默认第一个球颜色
    private final static int DEFAULT_ONE_BALL_COLOR = Color.argb(255, 247, 48, 46);
    //默认第二个球颜色
    private final static int DEFAULT_TWO_BALL_COLOR = Color.argb(255, 30, 199, 247);
    //默认是动画执行时间
    private final static long DEFUALT_ANIMATOR_DURATION = 1000;

    //当前画笔
    private Paint mPaint;
    //当前球最大半径
    private float mMaxRadius = DEFUALT_MAX_RADIUS;
    //当前球最小半径
    private float mMinRadius = DEFUALT_MIN_RADIUS;
    //两球心间隔距离
    private float mDistance = DEFAULT_DISTANCE;
    //动画时间
    private long mDuration = DEFUALT_ANIMATOR_DURATION;
    //第一个球颜色
    private int mOneColor = DEFAULT_ONE_BALL_COLOR;
    //第二个球颜色
    private int mTwoColor = DEFAULT_TWO_BALL_COLOR;

    private Ball mOneBall;
    private Ball mTwoBall;
    private int mCenterX;
    private int mCenterY;

    private AnimatorSet animatorSet;

    public BallRotationAnim(Context context) {
        this(context, null);
    }

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

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

    private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BallRotationAnim);
        mMaxRadius = typedArray.getDimension(R.styleable.BallRotationAnim_max_radius, DEFUALT_MAX_RADIUS);
        mMinRadius = typedArray.getDimension(R.styleable.BallRotationAnim_min_radius, DEFUALT_MIN_RADIUS);
        mOneColor = typedArray.getColor(R.styleable.BallRotationAnim_one_color, DEFAULT_ONE_BALL_COLOR);
        mTwoColor = typedArray.getColor(R.styleable.BallRotationAnim_two_color, DEFAULT_TWO_BALL_COLOR);
        mDistance = typedArray.getDimension(R.styleable.BallRotationAnim_distance, DEFAULT_DISTANCE);
        mDuration = typedArray.getInt(R.styleable.BallRotationAnim_duration, (int) DEFUALT_ANIMATOR_DURATION);
        typedArray.recycle();

        mOneBall = new Ball();
        mTwoBall = new Ball();
        mOneBall.color = mOneColor;
        mTwoBall.color = mTwoColor;

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        initAnimator();
    }

    private void initAnimator() {
        //球移动到中间的半径
        float centerRadius = (mMaxRadius + mMinRadius) * 0.5f;

        //第一个球缩放动画
        ObjectAnimator oneScaleAnimator = ObjectAnimator.ofFloat(mOneBall, "radius", centerRadius, mMaxRadius, centerRadius, mMinRadius, centerRadius);
        //无线循环
        oneScaleAnimator.setRepeatCount(ValueAnimator.INFINITE);

        //第一个球移动动画
        ValueAnimator oneTranslationAnimtor = ValueAnimator.ofFloat(-1, 0, 1, 0, -1);
        oneTranslationAnimtor.setRepeatCount(ValueAnimator.INFINITE);
        oneTranslationAnimtor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                float x = mCenterX + mDistance * value;
                mOneBall.centerX = x;
                invalidate();
            }
        });


        //第二个球缩放动画
        ObjectAnimator twoScaleAnimator = ObjectAnimator.ofFloat(mTwoBall, "radius", centerRadius, mMinRadius, centerRadius, mMaxRadius, centerRadius);
        twoScaleAnimator.setRepeatCount(ValueAnimator.INFINITE);

        //第二个球移动动画
        ValueAnimator twoTranslationAnimtor = ValueAnimator.ofFloat(1, 0, -1, 0, 1);
        twoTranslationAnimtor.setRepeatCount(ValueAnimator.INFINITE);
        twoTranslationAnimtor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                float x = mCenterX + mDistance * value;
                mTwoBall.centerX = x;
            }
        });

        animatorSet = new AnimatorSet();
        animatorSet.playTogether(oneScaleAnimator, oneTranslationAnimtor, twoScaleAnimator, twoTranslationAnimtor);
        animatorSet.setDuration(mDuration);
        animatorSet.setInterpolator(new DecelerateInterpolator());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mCenterX = getMeasuredWidth() / 2;
        mCenterY = getMeasuredHeight() / 2;
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        //先画半径小的球,产生旋转效果
        if (mOneBall.radius > mTwoBall.radius) {
            mPaint.setColor(mTwoBall.color);
            canvas.drawCircle(mTwoBall.centerX, mCenterY, mTwoBall.radius, mPaint);
            mPaint.setColor(mOneBall.color);
            canvas.drawCircle(mOneBall.centerX, mCenterY, mOneBall.radius, mPaint);
        } else {
            mPaint.setColor(mOneBall.color);
            canvas.drawCircle(mOneBall.centerX, mCenterY, mOneBall.radius, mPaint);
            mPaint.setColor(mTwoBall.color);
            canvas.drawCircle(mTwoBall.centerX, mCenterY, mTwoBall.radius, mPaint);
        }
    }

    /**
     * 监听view的显示隐藏
     *
     * @param changedView
     * @param visibility
     */
    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (visibility == GONE || visibility == INVISIBLE) {
            stopAnimator();
        } else {
            startAnimator();
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        startAnimator();
    }

    /**
     * 开始动画
     */
    private void startAnimator() {
        if (getVisibility() != VISIBLE || animatorSet == null || animatorSet.isRunning())
            return;
        animatorSet.start();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        stopAnimator();
    }

    /**
     * 停止动画
     */
    private void stopAnimator() {
        if (animatorSet == null)
            return;
        animatorSet.end();
    }

    /**
     * 球实体类
     */
    public class Ball {
        public float radius;//半径
        public float centerX;//圆心,x轴坐标
        public int color;//颜色

        public float getRadius() {
            return radius;
        }

        public void setRadius(float radius) {
            this.radius = radius;
        }

        public float getCenterX() {
            return centerX;
        }

        public void setCenterX(float centerX) {
            this.centerX = centerX;
        }

        public int getColor() {
            return color;
        }

        public void setColor(int color) {
            this.color = color;
        }
    }
}

使用非常简单:

<com.example.twoballrotationanim.widget.BallRotationAnim
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        app:distance="30dp"
        app:duration="800"
        app:one_color="#ff0000"
        app:two_color="#0000ff" />

代码下载

你可能感兴趣的:(Android自定义控件)