自定义控件是每个 Android 应用开发者的必备技能,所以一起来试着手写自定义控件,挑战自定义 View 中最好玩的 onDraw.
我们仿照 QQ 计步器的样式来做,主要熟悉画笔(Paint)的使用技巧
在这里感谢红橙Darren老师的指导
// 自定义计步器控件属性
// 背景圆弧颜色
// 前景圆弧颜色
// 圆弧宽度
// 字体颜色
// 字体大小
// 最大步数
// 当前步数
重写三个构造方法,读取自定义属性,重写onDraw
public FootStepCounterView(Context context) {
this(context,null);
}
public FootStepCounterView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public FootStepCounterView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomFilterView);
bgViewColor = typedArray.getColor(R.styleable.CustomFilterView_backgroundViewColor, Color.RED);
fontViewColor = typedArray.getColor(R.styleable.CustomFilterView_fontViewColor,Color.YELLOW);
stepViewColor = typedArray.getColor(R.styleable.CustomFilterView_stepViewTextColor,Color.YELLOW);
stepViewTextSize = typedArray.getDimensionPixelSize(R.styleable.CustomFilterView_stepViewTextSize,100);
stepViewTextColor = typedArray.getColor(R.styleable.CustomFilterView_stepViewTextColor, Color.YELLOW);
stepViewArcWidth = typedArray.getDimensionPixelOffset(R.styleable.CustomFilterView_stepViewArcWidth,10);
maxStep = typedArray.getInt(R.styleable.CustomFilterView_maxStepCount,DEFAULT_MAX_STEP);
mCurrentFootstep = typedArray.getInt(R.styleable.CustomFilterView_currentStepCount, DEFAULT_MAX_STEP);
typedArray.recycle();
init();
}
private void init() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
stringBuffer = new StringBuffer();
}
private void drawBgArc(Canvas canvas) {
// 设置画笔: 宽度
mPaint.setStrokeWidth(stepViewArcWidth);
// 始末端圆角
mPaint.setStrokeCap(Paint.Cap.ROUND);
// 拐角处圆角
// mPaint.setStrokeJoin(Paint.Join.ROUND);
// 实线
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(bgViewColor);
// 设置可操作区域
// RectF rectF = new RectF(left,top,right,bottom);
canvas.drawArc(rectF,135,270,false,mPaint);
}
@Override
protected void onDraw(Canvas canvas){
// 绘制背景圆弧
drawBgArc(canvas);
// 绘制上层圆弧
drawFontArc(canvas);
// 绘制文字
drawText(canvas);
}
private void drawFontArc(Canvas canvas) {
mPaint.setColor(fontViewColor);
float percentage = (float) ((double)getCurrentFootstep()/(double) maxStep)*100;
canvas.drawArc(rectF,135,(percentage*270)/100,false,mPaint);
}
绘制文字时需要注意基线的位置,在这个控件中基线位于整个控件空心点偏下的位置.
private void drawText(Canvas canvas) {
// 重置画笔
mPaint.reset();
mPaint.setAntiAlias(true);
mPaint.setTextSize(stepViewTextSize);
mPaint.setColor(stepViewColor);
// 设置基线
stringBuffer.append(getCurrentFootstep());
stringBuffer.append("步");
Rect rect = new Rect();
mPaint.getTextBounds(stringBuffer.toString(),0, stringBuffer.toString().length(),rect);
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
int baselineX = ( stepViewWidth - rect.width())/2;
int baselineY = (stepViewHeight / 2) + (int) (fontMetrics.bottom-fontMetrics.top)/4;
canvas.drawText(stringBuffer.toString(),baselineX,baselineY,mPaint);
stringBuffer.setLength(0);
}
计步器需要提供一个设置步数的方法,并在调用此方法时重绘控件来刷新数据
// 获取当前步数
public synchronized int getCurrentFootstep() {
return mCurrentFootstep;
}
// 设置当前步数
public synchronized void setCurrentFootstep(int mCurrentFootstep) {
this.mCurrentFootstep = mCurrentFootstep;
invalidate();
}