package external.otherview; import java.util.ArrayList; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.view.View; /** * 圆形进度条 * * @author planet */ public class Win8ProgressBar extends View { static final String TAG = Win8ProgressBar.class.getSimpleName(); /** * 帧率=1000/delayMillis 帧率越快,旋转速度也就越快 */ private int mDelayMillis = 30; private Handler mHandler; private ArrayList<Entity> mEntityList; private int mWidth = 0; // private int height = 0; private int mR = 15; private int mShift = 20; private int mRadius = 3; private int mColor = Color.WHITE; private long mTime = 0; private boolean mStarted = false; public Win8ProgressBar(Context context) { super(context); init(null); } public Win8ProgressBar(Context context, AttributeSet attrs) { super(context, attrs); init(attrs); } public Win8ProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); mWidth = getLayoutParams().width; // height = getLayoutParams().height; if (mWidth > 0) { // 根据view宽度定义小球的半径 if (mWidth < 50) { mRadius = 3; } else if (mWidth < 80) { mRadius = 4; } else { mRadius = 5; } // radius = width<80?2:4; mR = mWidth / 2 - mRadius * 2; if (mR <= 0) mR = 15; mShift = mWidth / 2; } } private void init(AttributeSet attrs) { // 获取设置的background作为小球颜色,然后将view自身背景设置成透明色 if (attrs != null) { String v = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "background"); if (v != null) { if (v.startsWith("#")) { mColor = Color.parseColor(v); } else { mColor = getResources().getColor(Integer.parseInt(v.replaceAll("@", ""))); } } setBackgroundResource(android.R.color.transparent); } mHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { for (Entity e : mEntityList) { e.update(); } invalidate(); mHandler.sendEmptyMessageDelayed(0, mDelayMillis); mTime += mDelayMillis; return false; } }); } public void setColor(int color) { this.mColor = color; } /** * 结束动画 */ public void stop() { mHandler.removeMessages(0); mStarted = false; invalidate(); } public boolean isStart() { return mStarted; } /** * 重新开始动画 */ public void start() { if (mStarted) return; mStarted = true; mTime = 0; mEntityList = new ArrayList<Win8ProgressBar.Entity>(); float s = .25f; mEntityList.add(new Entity(0, mColor, 0)); mEntityList.add(new Entity(1 * s, mColor, mDelayMillis * 4)); mEntityList.add(new Entity(2 * s, mColor, mDelayMillis * 8)); mEntityList.add(new Entity(3 * s, mColor, mDelayMillis * 12)); mEntityList.add(new Entity(4 * s, mColor, mDelayMillis * 16)); mHandler.sendEmptyMessage(0); } @Override protected void onDraw(Canvas canvas) { for (Entity e : mEntityList) { e.draw(canvas); } super.onDraw(canvas); } class Entity { private float x; private float y; private int color; private Paint paint; private double sp = 0; private long delay; // 动画一共三个阶段0~2 private int sec = 0; // 每个阶段pec从0~1 private float pec = 0; boolean visiable = true; public float getInterpolation(float input) { return (float) (Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; } public Entity(float sp, int color, int delay) { paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.FILL); this.color = color; this.sp = sp; this.delay = delay; paint.setColor(this.color); } public void update() { if (mTime < delay) return; visiable = true; // pec这个变量是步进值,值越大,旋转速度也越快,可以跟delayMillis配合使用 pec += 0.03; if (pec > 1) { pec = 0; sec = ++sec == 3 ? 0 : sec; delay = sec == 0 ? mTime + mDelayMillis * 22 : mTime + mDelayMillis * 3; visiable = sec == 0 ? false : true; } // sec=0从0.5pi开始,sec=1从1.5pi开始,sec=2从1pi开始 double θ = Math.PI * .5 + (sec == 0 ? 0 : sec * Math.PI / sec) - (sec == 0 ? 0 : sp) // sec=0,sec=2移动1pi, sec=1移动2pi + (Math.PI * (sec == 1 ? 2 : 1) - (sec == 0 ? sp : 0) + (sec == 2 ? sp : 0)) * getInterpolation(pec); x = (float) (mR / 2 * Math.cos(θ)) + mShift / 2; y = (float) (mR / 2 * Math.sin(θ)) + mShift / 2; } public void draw(Canvas canvas) { if (!visiable || x == 0 || y == 0) return; canvas.save(); canvas.translate(x, y); canvas.drawCircle(x, y, mRadius, paint); canvas.restore(); } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (getVisibility() == View.VISIBLE) { start(); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); stop(); } }