仿照win8的進度條自定義了一個progressbar,進度條默是白色,修改android:background屬性可以設置進度條顏色。截了幾張圖,一些細節模仿地還不夠到位:
/**
* 圓形進度條
* @author planet
*
*/
public class IndeterminateProgressBar extends View{
static final String TAG = "ProgressBar";
/**
* 幀率=1000/delayMillis
* 幀率越快,旋轉速度也就越快
*/
private int delayMillis = 30;
private Handler mHandler;
private ArrayList<Entity> entities;
private int width = 0;
// private int height = 0;
private int r = 15;
private int shift = 20;
private int radius = 3;
private int color = Color.WHITE;
private long time = 0;
private boolean started = false;
public IndeterminateProgressBar(Context context) {
super(context);
init(null);
}
public IndeterminateProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public IndeterminateProgressBar(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);
width = getLayoutParams().width;
// height = getLayoutParams().height;
if(width>0){
//根據view寬度定義小球的半徑
if(width<50){
radius = 2;
}else if(width<80){
radius = 3;
}else{
radius = 4;
}
//radius = width<80?2:4;
r = width/2-radius*2;
if(r<=0) r = 15;
shift = width/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("#")){
color = Color.parseColor(v);
}else{
color = 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 : entities){
e.update();
}
invalidate();
mHandler.sendEmptyMessageDelayed(0, delayMillis);
time += delayMillis;
return false;
}
});
}
public void setColor(int color){
this.color = color;
}
/**
* 結束動畫
*/
public void stop(){
mHandler.removeMessages(0);
started = false;
invalidate();
}
public boolean isStart(){
return started;
}
/**
* 重新開始動畫
*/
public void start(){
if(started) return;
started = true;
time = 0;
entities = new ArrayList<IndeterminateProgressBar.Entity>();
float s = .25f;
entities.add(new Entity(0, color, 0));
entities.add(new Entity(1*s, color, delayMillis*4));
entities.add(new Entity(2*s, color, delayMillis*8));
entities.add(new Entity(3*s, color, delayMillis*12));
entities.add(new Entity(4*s, color, delayMillis*16));
mHandler.sendEmptyMessage(0);
}
@Override
protected void onDraw(Canvas canvas) {
for(Entity e : entities){
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(time<delay) return;
visiable = true;
//pec這個變量是步進值,值越大,旋轉速度也越快,可以跟delayMillis配合使用
pec+= 0.03;
if(pec>1){
pec = 0;
sec=++sec==3?0:sec;
delay = sec==0?time+delayMillis*22:time+delayMillis*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) (r/2*Math.cos(θ))+shift/2;
y = (float) (r/2*Math.sin(θ))+shift/2;
}
public void draw(Canvas canvas){
if(!visiable || x==0 || y==0) return;
canvas.save();
canvas.translate(x, y);
canvas.drawCircle(x, y, radius, paint);
canvas.restore();
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if(getVisibility() == View.VISIBLE){
start();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
stop();
}
}