好吧,久不动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~~~
时间: 2024-10-14 21:58:48