自定义View对于Android程序猿来说都应该了解的,或者说一定要掌握。虽然Google提供的控件可以满足日常开发需求,但是总有些奇葩需求肯定是满足不了的,所以对于自定义View的开发,就必不可少了。
关于自定义View的基础学习推荐GcsSloop自定义View系列
首先看下面效果图

实现上图的效果参考这篇文章
再来这个效果图

上面效果图是根据第一个Demo的扩展,具体源码会在文章结尾提供链接
最后一个效果图

这个自定义View是模仿QQ运动的那个界面
下面具体对模仿QQ运动这个View实现步骤
1.初始化所需参数
//数据初始化
private void init(Context context){
//圆弧所需的矩形
mRect = new RectF();
//其他字的画笔
textGrayPaint = new Paint();
textGrayPaint.setAntiAlias(true);
textGrayPaint.setStyle(Paint.Style.FILL);
textGrayPaint.setColor(0xFFC6C1C3);
textGrayPaint.setTextAlign(Paint.Align.CENTER);
//排名的画笔
textSmallPaint = new Paint();
textSmallPaint.setAntiAlias(true);
textSmallPaint.setStyle(Paint.Style.FILL);
textSmallPaint.setColor(textColor);
textSmallPaint.setTextAlign(Paint.Align.CENTER);
//总步数的画笔
textBigPaint = new Paint();
textBigPaint.setAntiAlias(true);
textBigPaint.setStyle(Paint.Style.FILL);
textBigPaint.setColor(textColor);
textBigPaint.setTextAlign(Paint.Align.CENTER);
//外圆弧的画笔
outSideLinePaint = new Paint();
outSideLinePaint.setAntiAlias(true);
outSideLinePaint.setStyle(Paint.Style.STROKE);
outSideLinePaint.setColor(outCircleColor);
outSideLinePaint.setStrokeCap(Paint.Cap.ROUND);
//内圆弧的画笔
inSideLinePaint = new Paint();
inSideLinePaint.setAntiAlias(true);
inSideLinePaint.setStyle(Paint.Style.STROKE);
inSideLinePaint.setColor(inCircleColor);
inSideLinePaint.setStrokeCap(Paint.Cap.ROUND);
//竖条画笔
barPaint = new Paint();
barPaint.setAntiAlias(true);
barPaint.setStyle(Paint.Style.FILL);
barPaint.setColor(outCircleColor);
barPaint.setStrokeCap(Paint.Cap.ROUND);
//背景画笔
backgroundPaint = new Paint();
barPaint.setAntiAlias(true);
barPaint.setStyle(Paint.Style.FILL);
//虚线画笔
dashLinePaint = new Paint();
dashLinePaint.setAntiAlias(true);
dashLinePaint.setColor(Color.parseColor("#C1C1C1"));
dashLinePaint.setStyle(Paint.Style.STROKE);
dashLinePaint.setPathEffect(new DashPathEffect(new float[]{8, 4}, 0));//画虚线
//头像
headBitmap = BitmapFactory.decodeResource(context.getResources(),R.mipmap.icon_head);
}
2.测量View的宽高
//测量高度
private int getHeightMeasure(int measureSpec){
int result = getSuggestedMinimumHeight();
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode){
case MeasureSpec.UNSPECIFIED:
break;
case MeasureSpec.EXACTLY:
case MeasureSpec.AT_MOST:
result = (int) (specSize*0.7);
break;
}
return result;
}
//测量宽度
private int getWidthMeasure(int measureSpec){
int result = getSuggestedMinimumWidth();
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode){
case MeasureSpec.UNSPECIFIED:
break;
case MeasureSpec.EXACTLY:
case MeasureSpec.AT_MOST:
result = (int) (specSize*0.9);
break;
}
return result;
}
//计算所需各个数值大小
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
centerX = 0;
centerY = -height*heightScale;
mRect = new RectF(-width*widthScale,-width*widthScale+centerY,width*widthScale,width*widthScale+centerY);
arcStrokeWidth = width/200f*6;
textGraySize = width/200f*7;
textSmallSize = width/200f*8;
textBigSize = textSmallSize*3;
}
3.最后就是把界面画出来
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//设置各个paint所需的大小
textGrayPaint.setTextSize(textGraySize);
textSmallPaint.setTextSize(textSmallSize);
textBigPaint.setTextSize(textBigSize);
outSideLinePaint.setStrokeWidth(arcStrokeWidth);
inSideLinePaint.setStrokeWidth(arcStrokeWidth);
barPaint.setStrokeWidth(arcStrokeWidth);
paintBelowBackground(canvas);//画下层背景
paintUpBackground(canvas);//画上层背景
paintDashLine(canvas);//画虚线
paintBar(canvas);//画近七天的竖条
paintBottom(canvas);
canvas.translate(width/2,height/2); //移动坐标原点到中间
//画圆弧
Path path = new Path();
path.addArc(mRect,120,300);
canvas.drawPath(path,inSideLinePaint);
path.reset();
path.addArc(mRect,120,300*percent);
canvas.drawPath(path,outSideLinePaint);
//圆弧间的文字
textGrayPaint.setTextAlign(Paint.Align.CENTER);
textGrayPaint.setTextSize(textGraySize);
canvas.drawText("截至"+nowTime+"已走",0,-textBigSize+centerY,textGrayPaint);
canvas.drawText(totalText+"",0,textSmallSize/2+centerY,textBigPaint);
canvas.drawText("好友平均"+freAvgText+"步",0,textBigSize+centerY,textGrayPaint);
canvas.drawText("第",-textSmallSize/2*3+centerX,width*widthScale+centerY,textGrayPaint);
canvas.drawText(rankText+"",0+centerX,width*widthScale+centerY,textSmallPaint);
canvas.drawText("名",textSmallSize/2*3+centerX,width*widthScale+centerY,textGrayPaint);
}
上面只放了部分代码,完整代码地址
PS:模仿QQ运动这个只画出了界面,没有给出点击事件,有兴趣的同学可以自行浏览体验