Android开发——自定义view之环形等待控件的实现

本文主要讲述了如何实现Android 自定义view之环形等待控件,现在把实现思路和代码整理出来分享给Android程序员兄弟们,希望给他们的开发工作带来帮助。   

效果图如下:

Android自定义view之环形等待控件的实现

以上就是今天我们要实现的效果,乍一看是不是觉得高端大气上档次,完全没有什么头绪怎么去实现这么“高端”的东西。还会不定时的反问自己可以吗?对,你可以的。让我们一起来学习如何写这样的控件吧。

【前言】自定义view 的几个步骤

自定义view的属性在view 的构造方法中获取我们自定义的属性的值重写onMeasure方法(有时不需要重写这个方法)重写onDraw方法

【正文】

项目结构图奉上:

Android自定义view之环形等待控件的实现

Android自定义view之环形等待控件的实现

我们先来分析一下这个控件。这个控件主要有两种颜色,加载的速度,圆环的宽度,好像也没有其他属性值了。

1.自定义属性:attrs.xml

1 <span style="font-size: medium;"><!--?xml version=1.0 encoding=utf-8?--></span>

这里的format主要常见的有以下几种属性:reference 、color、boolean、dimension、float、integer、string、fraction、enum、flag。更多用法以及如何在初始化时获取相应的值,可以百度,这里不是我们的重点。

2.在构造方法中获取我们自定义的属性:CustomProgressbar.java

1 <span style="font-size: medium;">   // 设置第一圈颜色
2     private int mFirstColor=Color.GREEN;
3     // 设置第二圈颜色
4     private int mSecondColor=Color.RED;
5     // 设置圈的宽度
6     private int mCircleWidth=20;
7     // 设置颜色填充画笔
8     private Paint mPaint;
9     // 设置当前进度
10     private int mProgress;
11     // 设置当前进度加载速度
12     private int speed=20;
13     // 是否开始下一个
14     private boolean isNext = false;
15  
16     public CustomProgressbar(Context context, AttributeSet attrs) {
17         this(context, attrs, 0);
18     }
19  
20     public CustomProgressbar(Context context) {
21         this(context, null);
22     }
23  
24     /**
25      * 必要的初始化,获取一些自定义的值
26      *
27      * @param context
28      * @param attrs
29      * @param defStyle
30      */
31     public CustomProgressbar(Context context, AttributeSet attrs, int defStyle) {
32         super(context, attrs, defStyle);
33         // 获取自定义的属性集合
34         TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomProgressbar, defStyle, 0);
35         // 获取自定义属性的个数
36         int n = array.getIndexCount();
37         Log.i(test, 自定义属性的个数: + n);
38         // 遍历属性值
39         for (int i = 0; i < n; i++) {
40             int attr = array.getIndex(i);
41             Log.i(test, 自定义的属性为:+attr);
42             switch (attr) {
43             case R.styleable.CustomProgressbar_firstColor:
44                 // 获取第一圈颜色值
45                 mFirstColor = array.getColor(attr, Color.GREEN);
46                 break;
47             case R.styleable.CustomProgressbar_secondColor:
48                 // 获取第一圈颜色值
49                 mSecondColor = array.getColor(attr, Color.RED);
50                 break;
51             case R.styleable.CustomProgressbar_circleWidth:
52                 // 设置默认圈的宽度为20px
53                 mCircleWidth = array.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 20, getResources().getDisplayMetrics()));
54                 break;
55             case R.styleable.CustomProgressbar_speed:
56                 // 获取默认加载速度
57                 speed = array.getInt(attr, 20);
58                 break;
59             }
60         }
61         // 回收
62         array.recycle();
63         mPaint = new Paint();
64         // 绘图线程 此线程为耗时线程,放在子线程中执行,防止主线程的卡顿
65         new Thread() {
66             public void run() {
67                 while (true) {
68                     mProgress++;
69                     if (mProgress == 360) {
70                         mProgress = 0;
71                         // 如果没有开始下一个,则设置isNext为true
72                         if (!isNext) {
73                             isNext = true;
74                         else {
75                             isNext = false;
76                         }
77                     }
78                     // 刷新UI
79                     // postInvalidate()此方法可以直接在UI线程调用,invalidate()则需要在handler中进行调用
80                     postInvalidate();
81                     try {
82                         Thread.sleep(speed);
83                     catch (InterruptedException e) {
84                         e.printStackTrace();
85                     }
86                 }
87             }
88         }.start();
89     }</span>

很多童鞋肯定会问,为什么这个操作要放在thread里进行操作?重写view是一个耗时操作,所以我们这里就直接放在子线程里进行重绘了,防止程序卡死。还有一个需要注意的就是postInvalidate()方法。postInvalidate()此方法可以直接在UI线程调用,invalidate()则需要在handler中进行调用,想要了解更多的童鞋也可以自己百度两者之间的区别。

3.重写onMeasure方法:本例中没有用到重写onMeasure方法,此处就不贴代码了。

4.重写onDraw方法,进行view 的绘制:CustomProgressbar.java

1 <span style="font-size: medium;">@Override
2     protected void onDraw(Canvas canvas) {
3         // 获取圆心的x坐标
4         int center = getWidth() / 2;
5         // 获取圆的半径
6         int radius = center - mCircleWidth / 2;
7         // 设置填充的宽度
8         mPaint.setStrokeWidth(mCircleWidth);
9         mPaint.setAntiAlias(true);
10         // 设置填充的style
11         mPaint.setStyle(Paint.Style.STROKE);
12         // new RectF(left, top, right, bottom) 为距离x轴,y轴之间的距离
13         // 定义rect的形状
14         RectF f = new RectF(center - radius, center - radius, center + radius, center + radius);
15         if (!isNext) {
16             // 第一圈颜色完整,第二圈颜色跑
17             mPaint.setColor(mFirstColor);// 设置画笔颜色
18             // 画出圆环
19             canvas.drawCircle(center, center, radius, mPaint);
20             // 设置圆环颜色
21             mPaint.setColor(mSecondColor);
22             /*
23              * public void drawArc(RectF oval, float startAngle, float sweepAngle,
24              * boolean useCenter, Paint paint) oval :指定圆弧的外轮廓矩形区域。 startAngle:
25              * 圆弧起始角度,单位为度。 sweepAngle: 圆弧扫过的角度,顺时针方向,单位为度。 useCenter:
26              * 如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形。 paint: 绘制圆弧的画板属性,如颜色,是否填充等。
27              */
28             canvas.drawArc(f, -90, mProgress, false, mPaint);
29         } else {
30             // 第一圈颜色完整,第二圈颜色跑
31             mPaint.setColor(mSecondColor);// 设置画笔颜色
32             // 画出圆环
33             canvas.drawCircle(center, center, radius, mPaint);
34             // 设置圆环颜色
35             mPaint.setColor(mFirstColor);
36             /*
37              * public void drawArc(RectF oval, float startAngle, float sweepAngle,
38              * boolean useCenter, Paint paint) oval :指定圆弧的外轮廓矩形区域。 startAngle:
39              * 圆弧起始角度,单位为度。 sweepAngle: 圆弧扫过的角度,顺时针方向,单位为度。 useCenter:
40              * 如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形。 paint: 绘制圆弧的画板属性,如颜色,是否填充等。
41              */
42             canvas.drawArc(f, -90, mProgress, false, mPaint);
43         }
44     }</span>

这里关于drawArc的方法,我已经加了详细的注释,不明白的同学可以自己百度一下。

由于上面贴的是片段代码,这里给出CustomProgressbar.java的全部代码:

1 <span style="font-size: medium;">package com.beyole.view;
2  
3 import android.content.Context;
4 import android.content.res.TypedArray;
5 import android.graphics.Canvas;
6 import android.graphics.Color;
7 import android.graphics.Paint;
8 import android.graphics.RectF;
9 import android.util.AttributeSet;
10 import android.util.Log;
11 import android.util.TypedValue;
12 import android.view.View;
13  
14 import com.beyole.circlewaitting.R;
15  
16 public class CustomProgressbar extends View {
17  
18     // 设置第一圈颜色
19     private int mFirstColor=Color.GREEN;
20     // 设置第二圈颜色
21     private int mSecondColor=Color.RED;
22     // 设置圈的宽度
23     private int mCircleWidth=20;
24     // 设置颜色填充画笔
25     private Paint mPaint;
26     // 设置当前进度
27     private int mProgress;
28     // 设置当前进度加载速度
29     private int speed=20;
30     // 是否开始下一个
31     private boolean isNext = false;
32  
33     public CustomProgressbar(Context context, AttributeSet attrs) {
34         this(context, attrs, 0);
35     }
36  
37     public CustomProgressbar(Context context) {
38         this(context, null);
39     }
40  
41     /**
42      * 必要的初始化,获取一些自定义的值
43      *
44      * @param context
45      * @param attrs
46      * @param defStyle
47      */
48     public CustomProgressbar(Context context, AttributeSet attrs, int defStyle) {
49         super(context, attrs, defStyle);
50         // 获取自定义的属性集合
51         TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomProgressbar, defStyle, 0);
52         // 获取自定义属性的个数
53         int n = array.getIndexCount();
54         Log.i(test, 自定义属性的个数: + n);
55         // 遍历属性值
56         for (int i = 0; i < n; i++) {
57             int attr = array.getIndex(i);
58             Log.i(test, 自定义的属性为:+attr);
59             switch (attr) {
60             case R.styleable.CustomProgressbar_firstColor:
61                 // 获取第一圈颜色值
62                 mFirstColor = array.getColor(attr, Color.GREEN);
63                 break;
64             case R.styleable.CustomProgressbar_secondColor:
65                 // 获取第一圈颜色值
66                 mSecondColor = array.getColor(attr, Color.RED);
67                 break;
68             case R.styleable.CustomProgressbar_circleWidth:
69                 // 设置默认圈的宽度为20px
70                 mCircleWidth = array.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 20, getResources().getDisplayMetrics()));
71                 break;
72             case R.styleable.CustomProgressbar_speed:
73                 // 获取默认加载速度
74                 speed = array.getInt(attr, 20);
75                 break;
76             }
77         }
78         // 回收
79         array.recycle();
80         mPaint = new Paint();
81         // 绘图线程 此线程为耗时线程,放在子线程中执行,防止主线程的卡顿
82         new Thread() {
83             public void run() {
84                 while (true) {
85                     mProgress++;
86                     if (mProgress == 360) {
87                         mProgress = 0;
88                         // 如果没有开始下一个,则设置isNext为true
89                         if (!isNext) {
90                             isNext = true;
91                         else {
92                             isNext = false;
93                         }
94                     }
95                     // 刷新UI
96                     // postInvalidate()此方法可以直接在UI线程调用,invalidate()则需要在handler中进行调用
97                     postInvalidate();
98                     try {
99                         Thread.sleep(speed);
100                     catch (InterruptedException e) {
101                         e.printStackTrace();
102                     }
103                 }
104             }
105         }.start();
106     }
107  
108     @Override
109     protected void onDraw(Canvas canvas) {
110         // 获取圆心的x坐标
111         int center = getWidth() / 2;
112         // 获取圆的半径
113         int radius = center - mCircleWidth / 2;
114         // 设置填充的宽度
115         mPaint.setStrokeWidth(mCircleWidth);
116         mPaint.setAntiAlias(true);
117         // 设置填充的style
118         mPaint.setStyle(Paint.Style.STROKE);
119         // new RectF(left, top, right, bottom) 为距离x轴,y轴之间的距离
120         // 定义rect的形状
121         RectF f = new RectF(center - radius, center - radius, center + radius, center + radius);
122         if (!isNext) {
123             // 第一圈颜色完整,第二圈颜色跑
124             mPaint.setColor(mFirstColor);// 设置画笔颜色
125             // 画出圆环
126             canvas.drawCircle(center, center, radius, mPaint);
127             // 设置圆环颜色
128             mPaint.setColor(mSecondColor);
129             /*
130              * public void drawArc(RectF oval, float startAngle, float sweepAngle,
131              * boolean useCenter, Paint paint) oval :指定圆弧的外轮廓矩形区域。 startAngle:
132              * 圆弧起始角度,单位为度。 sweepAngle: 圆弧扫过的角度,顺时针方向,单位为度。 useCenter:
133              * 如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形。 paint: 绘制圆弧的画板属性,如颜色,是否填充等。
134              */
135             canvas.drawArc(f, -90, mProgress, false, mPaint);
136         } else {
137             // 第一圈颜色完整,第二圈颜色跑
138             mPaint.setColor(mSecondColor);// 设置画笔颜色
139             // 画出圆环
140             canvas.drawCircle(center, center, radius, mPaint);
141             // 设置圆环颜色
142             mPaint.setColor(mFirstColor);
143             /*
144              * public void drawArc(RectF oval, float startAngle, float sweepAngle,
145              * boolean useCenter, Paint paint) oval :指定圆弧的外轮廓矩形区域。 startAngle:
146              * 圆弧起始角度,单位为度。 sweepAngle: 圆弧扫过的角度,顺时针方向,单位为度。 useCenter:
147              * 如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形。 paint: 绘制圆弧的画板属性,如颜色,是否填充等。
148              */
149             canvas.drawArc(f, -90, mProgress, false, mPaint);
150         }
151     }
152 }</span>

自定义的控件已经定义结束,接下来就是如何调用我们写的view了,首先,在我们的主布局文件:activity_main.xml中进行引用:

1  

这里注意,我们定义了自己的命名控件,也就是

1 <span style="font-size: medium;"> xmlns:beyole=http://schemas.android.com/apk/res/com.beyole.circlewaitting</span>

这里的com.beyole.circlewaitting就是我们应用程序的包名。如何知道我们应用程序的包名?直接在AndroidManifest.xml文件中
Android自定义view之环形等待控件的实现

主布局文件里面没有更改内容:MainActivity.java

1 <span style="font-size: medium;">package com.beyole.circlewaitting;
2  
3 import android.app.Activity;
4 import android.os.Bundle;
5  
6 public class MainActivity extends Activity {
7  
8     @Override
9     protected void onCreate(Bundle savedInstanceState) {
10         super.onCreate(savedInstanceState);
11         setContentView(R.layout.activity_main);
12     }
13 }</span>

本文到此结束,需要的朋友可以参考下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值