自定义view——实现半圆形进度条

图表控件很多,这个多少能跟图表控件扯上边吧。
废话不多说,看图:
这里写图片描述

上面可以看到效果,支持各种自定义,支持点击

这里没有用到 自定义属性。有兴趣的可以自己设置下。直接看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
public class CircleBar extends View {
private static final String TAG = "CircleBar";
private RectF mColorWheelRectangle = new RectF();//圆圈的矩形范围
private Paint mDefaultWheelPaint;////绘制底部灰色圆圈的画笔
private Paint mColorWheelPaint;//绘制蓝色扇形的画笔
private Paint textPaint;//中间数值文字的画笔
private Paint textDesPaint;//描述文字的画笔
private float mColorWheelRadius;
private float circleStrokeWidth;//圆圈的线条粗细
private float pressExtraStrokeWidth;
private int mTextColor = getResources().getColor(R.color.blue);//默认文字颜色
private int mWheelColor = getResources().getColor(R.color.blue);//默认圆环颜色
private String mText;
private String mTextDes;//文字的描述
private int mTextDesSize;//描述文字的大小
private int mCount;//为了做动画
private float mSweepAnglePer;//扇形弧度百分比
private float mSweepAngle;//扇形弧度
private int mTextSize;//文字大小
private int mDistance;// 上下文字的距离
BarAnimation anim;//动画
private int TIME = 1000;//时间
public CircleBar(Context context) {
super(context);
init(null, 0);
}
public CircleBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public CircleBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs, defStyle);
}
private void init(AttributeSet attrs, int defStyle) {
//初始化一些值
circleStrokeWidth = dip2px(getContext(), 10);
pressExtraStrokeWidth = dip2px(getContext(), 2);
mTextSize = dip2px(getContext(), 30);
mTextDesSize = dip2px(getContext(), 15);
mDistance = dip2px(getContext(), 30);//文字距离
//外圆环的画笔
mColorWheelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mColorWheelPaint.setColor(mWheelColor);
mColorWheelPaint.setStyle(Style.STROKE);
mColorWheelPaint.setStrokeWidth(circleStrokeWidth);//圆圈的线条粗细
mColorWheelPaint.setStrokeCap(Paint.Cap.ROUND);//开启显示边缘为圆形
//默认圆的画笔
mDefaultWheelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mDefaultWheelPaint.setColor(getResources().getColor(R.color.gray));
mDefaultWheelPaint.setStyle(Style.STROKE);
mDefaultWheelPaint.setStrokeWidth(circleStrokeWidth);//圆圈的线条粗细
mDefaultWheelPaint.setStrokeCap(Paint.Cap.ROUND);//开启显示边缘为圆形
//数值的画笔
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
textPaint.setColor(mTextColor);
textPaint.setStyle(Style.FILL_AND_STROKE);
textPaint.setTextAlign(Align.LEFT);
textPaint.setTextSize(mTextSize);
//描述文字的画笔
textDesPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
textDesPaint.setColor(getResources().getColor(R.color.gray));
textDesPaint.setStyle(Style.FILL_AND_STROKE);
textDesPaint.setTextSize(mTextDesSize);
textDesPaint.setTextAlign(Align.LEFT);
mText = "0";
mTextDes = "本次考试";
mSweepAngle = 0;
anim = new BarAnimation();
anim.setDuration(TIME);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawArc(mColorWheelRectangle, -180, 180, false, mDefaultWheelPaint);//画外接的圆环
canvas.drawArc(mColorWheelRectangle, -180, mSweepAnglePer, false, mColorWheelPaint);//画圆环
Rect bounds = new Rect();
String textstr = mCount + "";
textPaint.getTextBounds(textstr, 0, textstr.length(), bounds);
textDesPaint.getTextBounds(mTextDes, 0, mTextDes.length(), bounds);
// drawText各个属性的意思(文字,x坐标,y坐标,画笔)
canvas.drawText(
textstr + "",
(mColorWheelRectangle.centerX())
- (textPaint.measureText(textstr) / 2),
mColorWheelRectangle.centerY() + bounds.height() / 2 - 50,
textPaint);
canvas.drawText(mTextDes,
(mColorWheelRectangle.centerX())
- (textDesPaint.measureText(mTextDes) / 2),
mColorWheelRectangle.centerY() + bounds.height() / 2 - 50 - mDistance
, textDesPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = getDefaultSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
int min = Math.min(width, height);
setMeasuredDimension(min, min);
mColorWheelRadius = min - circleStrokeWidth - pressExtraStrokeWidth;
mColorWheelRectangle.set(circleStrokeWidth + pressExtraStrokeWidth, circleStrokeWidth + pressExtraStrokeWidth,
mColorWheelRadius, mColorWheelRadius);
}
@Override
public void setPressed(boolean pressed) {
Toast.makeText(getContext(), mText, Toast.LENGTH_SHORT).show();
}
public void startCustomAnimation() {
this.startAnimation(anim);
}
public void setText(String text) {
mText = text;
this.startAnimation(anim);
}
public void setDesText(String text) {
mTextDes = text;
this.startAnimation(anim);
}
public void setTextColor(int color) {
mTextColor = color;
textPaint.setColor(mTextColor);
}
public void setSweepAngle(float sweepAngle) {
mSweepAngle = sweepAngle;
}
public void setWheelColor(int color) {
this.mColorWheelPaint.setColor(color);
}
public class BarAnimation extends Animation {
/**
* Initializes expand collapse animation, has two types, collapse (1) and expand (0).
* 1 will collapse view and set to gone
*/
public BarAnimation() {
}
// * 动画类利用了applyTransformation参数中的interpolatedTime参数(从0到1)的变化特点,
// * 实现了该View的某个属性随时间改变而改变。原理是在每次系统调用animation的applyTransformation()方法时,
// * 改变mSweepAnglePer,mCount的值,
// * 然后调用postInvalidate()不停的绘制view。
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
//mSweepAnglePer,mCount这两个属性只是动画过程中要用到的临时属性,
//mText和mSweepAngle才是动画结束之后表示扇形弧度和中间数值的真实值。
if (interpolatedTime < 1.0f) {
mSweepAnglePer = interpolatedTime * mSweepAngle;
mCount = (int) (interpolatedTime * Float.parseFloat(mText));
} else {
mSweepAnglePer = mSweepAngle;
mCount = Integer.parseInt(mText);
}
postInvalidate();
}
}
public static int dip2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
}

注释非常清楚了。就不详细说明了。直接在在布局中使用。因为没有自定义属性,大家懂的。

源码地址飞机票

这里添加点击事件,通常继承自view都有onClick和oLongClick事件的。这里加进去就好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//监听器类接口
public static abstract interface OnClickListener{
public abstract void onClick(); //单击事件处理接口
}
OnClickListener listener=null; //监听器类对象
//实现这个View的监听器
public void setOnClickListener(OnClickListener listener){
this.listener = listener; //引用监听器类对象,在这里可以使用监听器类的对象
}