1. 程式人生 > >android 自定義控件之簡單的loading框

android 自定義控件之簡單的loading框

void stroke color mat pri htm img 溫習 時機

  好吧,久不動android,感覺自己已經快是條鹹魚了,趁著這周的開發任務已完成,下周的開發計劃未下來之際,來溫習一下android的自定義控件,於是就有了下面這個醜陋的玩意

  技術分享

  實現起來也是非常簡單,下面直接上代碼;

  

public class RingLoading extends View {
private final Context mContext;
private Paint mPaint;
private int outRadius;
private int innerRadius;
private int ringWidth = 20;
private int[] center = new int[2];
private float startIndex = -90;
private float endIndex = 0;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
invalidate();
}
};

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

public RingLoading(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public RingLoading(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
init();
}

private void init() {
mPaint = new Paint();
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
center[0] = width / 2;
center[1] = height / 2;
outRadius = (width > height ? height / 2 : width / 2) - ringWidth;
innerRadius = outRadius - ringWidth;
Logger.i("size", outRadius, innerRadius);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}

@Override
protected void onDraw(Canvas canvas) {
mPaint.setStrokeWidth(ringWidth);
mPaint.setARGB(0, 0, 0, 0);
canvas.drawCircle(center[0], center[1], innerRadius, mPaint);
mPaint.setARGB(255, 0, 0, 255);
canvas.drawCircle(center[0], center[1], outRadius, mPaint);
mPaint.setARGB(255, 255, 255, 255);
RectF rect = new RectF(ringWidth, ringWidth, ringWidth + 2 * outRadius, ringWidth + 2 *
outRadius);
canvas.drawArc(rect, startIndex, endIndex, false, mPaint);
super.onDraw(canvas);
}

public void startLoading() {
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
startIndex++;
if (startIndex < 0) {
endIndex ++;
} else if (startIndex > 180) {
endIndex--;
if (startIndex == 270) {
startIndex = -90;
endIndex = 0;
}
} else {
endIndex = 90;
}
mHandler.obtainMessage(1).sendToTarget();
}
};
timer.schedule(timerTask, 100, 5);
}
}

然後做一下簡單的分析吧,免得以後回過頭來看又要理一會。
  從實現效果來看,整個控件就是一個圓環,環上一個長短變化的白條,不停的轉啊轉的。如果白條長短不變的話,那就簡單了,直接放個圖,寫個旋轉動畫就OK了,關鍵是變化的啊,那就不得不弄個畫布,
自己來畫了,由於圓環和白條都是畫出來的,所以只要繼承View就好了;
  init()方法給畫筆初始化一些東西,這個沒什麽好說的,主要的實現代碼,都集中在onMeasure,onDraw和startLoading這三個方法裏,其中onMeasure獲得外圓和內園的半徑以及圓心的坐標,onDraw
方法根據半徑和坐標畫出圓環和旋轉的圓弧,startLoading方法不斷改變圓環的起始弧度和圓弧的弧長對應的圓心角,然後通知控件重繪(終止方法我這裏沒寫,調用timer的cancel方法就好了);
  知道了各個方法的作用,下面就具體進入這些方法分析一些細節:
  首先是onMeasure(int widthMeasureSpec, int heightMeasureSpec),這個方法是系統回調的,它會在適當的時機,將控件的寬高信息返回給我們,也就是這兩個參數,這兩個參數都是32位的整形,
其中,前兩位表示模式,可以通過MeasureSpec.getMode(int ...) 來獲取,模式分為三種,
              MeasureSpec.UNSPECIFIED,默認的,寬高未被父控件做任何限制;
              MeasureSpec.AT_MOST,在布局文件申明為android:layout_width = "wrap_content"時為此模式;
              MeasureSpec.EXACTLY,布局文件中指定具體的dp,或者為MATCH_PARENT值時是此模式;
MeasureSpec.getSize(int ...) 獲得控件的尺寸;

  然後是onDraw方法,  canvas.drawCircle(float centerX,floatCenterY,int radius,Paint) 這個是畫圓的方法,
             canvas.drawArc(RectF,startAngle,lenghtAngle,boolean userCenter,Paint),這個是畫弧線的方法,
了解了這兩個方法,onDraw的理解也不成為題。

最後就是startLoading了,這個方法就只是涉及邏輯的變化了,這個邏輯並不復雜,就不所說了,此次記錄就到這裏了,bye~~~

android 自定義控件之簡單的loading框