1. 程式人生 > >Android 自定義兩球旋轉動畫效果

Android 自定義兩球旋轉動畫效果

自定義一個兩球旋轉動畫效果,可以用於載入時的動畫展示

這裡寫圖片描述

先定義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" />

程式碼下載