android 自定义控件之简单的loading框
好吧,久不动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~~~