一個工具類就搞定:
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.graphics.Paint.Style;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.LinearInterpolator;
/**
* 模拟豎直平面内小球以一定初速度在重力作用下繞圓環做變速圓周運動 (從最低點減速到0上升到最高點再加速到初始值回到最低點)。
*
* @author jren
*
*/
public class AccelerateCircularView extends View {
/**
* 圓環的顔色
*/
private int mRingColor;
/**
* 小球的顔色
*/
private int mGlobuleColor;
/**
* 圓環半徑、小球的旋轉半徑
*/
private float mRingRadius;
/**
* 圓環寬度
*/
private float mRingWidth;
/**
* 小球的半徑
*/
private float mGlobuleRadius;
protected double currentAngle = -1;
/**
* 小球運動的周期
*/
private float mCycleTime;
private Paint mPaint;
public AccelerateCircularView(Context context) {
this(context, null);
}
public AccelerateCircularView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AccelerateCircularView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
TypedArray attrsArray = context.getTheme().obtainStyledAttributes(
attrs, R.styleable.AccelerateCircularView, defStyle, 0);
mRingColor = attrsArray.getColor(
R.styleable.AccelerateCircularView_ringColor, Color.GRAY);
mGlobuleColor = attrsArray.getColor(
R.styleable.AccelerateCircularView_globuleColor, Color.BLUE);
mRingWidth = attrsArray.getDimension(
R.styleable.AccelerateCircularView_ringWidth, TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
getResources().getDisplayMetrics()));
mGlobuleRadius = attrsArray.getDimension(
R.styleable.AccelerateCircularView_globuleRadius, TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6,
getResources().getDisplayMetrics()));
mCycleTime = attrsArray.getFloat(
R.styleable.AccelerateCircularView_cycleTime, 3000);
attrsArray.recycle();
mPaint = new Paint();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int mWidth = 0, mHeight = 0;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY) {
mWidth = widthSize;
} else {
mWidth = 169;
if (widthMode == MeasureSpec.AT_MOST) {
mWidth = Math.min(mWidth, widthSize);
}
}
if (heightMode == MeasureSpec.EXACTLY) {
mHeight = heightSize;
} else {
mHeight = 169;
if (heightMode == MeasureSpec.AT_MOST) {
mHeight = Math.min(mWidth, heightSize);
}
}
setMeasuredDimension(mWidth, mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int central = Math.min(getWidth(), getHeight()) / 2;
mRingRadius = central - mGlobuleRadius;
if (mGlobuleRadius < mRingWidth / 2) {// 小球嵌在環裡
mRingRadius = central - mRingWidth / 2;
}
mPaint.setStrokeWidth(mRingWidth);
mPaint.setStyle(Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setColor(mRingColor);
canvas.drawCircle(central, central, mRingRadius, mPaint);// 繪制圓環
mPaint.setStyle(Style.FILL);
mPaint.setAntiAlias(true);
mPaint.setColor(mGlobuleColor);
drawGlobule(canvas, central);// 繪制小球
}
/**
* 繪制小球,起始位置為圓環最低點
*
* @param central
*/
private void drawGlobule(Canvas canvas, float central) {
float cx = central + (float) (mRingRadius * Math.cos(currentAngle));
float cy = (float) (central + mRingRadius * Math.sin(currentAngle));
canvas.drawCircle(cx, cy, mGlobuleRadius, mPaint);
}
private ValueAnimator animator;
/**
* 旋轉小球
*/
public void startCirMotion() {
Log.e("TAG", "currentAngle:" + currentAngle);
if (currentAngle == -1) {
animator = ValueAnimator.ofFloat(90f, 450f);
animator.setDuration((long) mCycleTime).setRepeatCount(
ValueAnimator.INFINITE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float angle = (Float) animation.getAnimatedValue();
currentAngle = angle * Math.PI / 180;
invalidate();
}
});
// animator.setInterpolator(new LinearInterpolator());// 勻速旋轉
// 自定義開始減速到0後加速到初始值的Interpolator
LinearInterpolator lir = new LinearInterpolator();
animator.setInterpolator(lir);
animator.start();
}
}
public void stopAnimation()
{
if(animator!=null)
{
animator.end();
currentAngle =-1;
}
}
res/values/attrs.xml :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="ringColor" format="color"></attr>
<attr name="ringWidth" format="dimension"></attr>
<attr name="globuleColor" format="color"></attr>
<attr name="globuleRadius" format="dimension"></attr>
<attr name="cycleTime" format="float"></attr>
<declare-styleable name="AccelerateCircularView">
<attr name="ringColor" />
<attr name="ringWidth" />
<attr name="globuleColor" />
<attr name="globuleRadius" />
<attr name="cycleTime" />
</declare-styleable>
</resources>
The end !