自己闲着没事练习一下自定义view,就花了一天时间弄了一个方向盘的view,在这里分享给大家:
基本实现点击各个区域得到相应回调,界面比较简单,但是对于初学的我来说 花了不少功夫呢,希望对于初学的你来说有些许帮助。
先说下思路,我是由外向内画,先画外圈,再画内圈,之后画底部图形,ondraw中就是这样了由于做过cavas变化,就需要加入那一段。getMatrix
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(width / 2, height / 2);
// 获取测量矩阵(逆矩阵)
if (mMapMatrix.isIdentity()) {
canvas.getMatrix().invert(mMapMatrix);
}
Paint_outcircle(canvas);//画外部圆
Path p1 = Paint_outcircle_in(canvas);//画内圆
List p = Paint_bottom(canvas);//画底部小圈
Paint_sixArc(canvas, p, p1);//画6个扇形
}
画外部圆:就是先画一条圆弧,在计算左右两个点的坐标,再用quadTo方法画贝塞尔曲线,就完成了。
/**
* 画外部圆形
*
* @param canvas
*/
private void Paint_outcircle(Canvas canvas) {
Path path = new Path();
path.addArc(new RectF(-radius_out, -radius_out, radius_out, radius_out), startAngle, -sweepAngle);//里面那条
PathMeasure pm = new PathMeasure(path, false);
float[] pos = new float[2];
pm.getPosTan(0, pos, null);
float x1 = pos[0];
float y1 = pos[1];
pm.getPosTan(pm.getLength(), pos, null);
float x2 = pos[0];
float y2 = pos[1];
Log.e("skl", "--------" + x1 + "," + y1 + "," + x2 + "," + y2);
Path bse = new Path();
bse.moveTo(x1, y1);
bse.quadTo(0, 180, x2, y2);
path.addPath(bse);
path.setFillType(Path.FillType.EVEN_ODD);
canvas.drawPath(path, mPaint_back);//一条封闭贝塞尔+圆弧
}
画内部圆:就是把半径整体缩小一点,但是不画路径,这个画路径的方法我注释了,只是用来看效果的方便理解。最后加path传出去。后面有用(这整个方法其实就是为了把psth传出去)。
/**
* 画内部圆形
*
* @param canvas
*/
private Path Paint_outcircle_in(Canvas canvas) {
Path path = new Path();
path.addArc(new RectF(-radius_mid, -radius_mid, radius_mid, radius_mid), 65, -310);//里面那条
PathMeasure pm = new PathMeasure(path, false);
float[] pos = new float[2];
pm.getPosTan(0, pos, null);
float x1 = pos[0];
float y1 = pos[1];
pm.getPosTan(pm.getLength(), pos, null);
float x2 = pos[0];
float y2 = pos[1];
Log.e("skl", "--------" + x1 + "," + y1 + "," + x2 + "," + y2);
Path bse = new Path();
bse.moveTo(x1, y1);
bse.quadTo(0, 150, x2, y2);
path.addPath(bse);
path.setFillType(Path.FillType.EVEN_ODD);
// canvas.drawPath(path, mPaint_back2);//一条封闭贝塞尔+圆弧
return path;
}
画底部小圆:就是图形下半段那个特殊图形,我是用两个圆path相减得到的。为了跟后面做path相计算,这边传出去了一个list
private List Paint_bottom(Canvas canvas) {
Path circle1 = new Path();
circle1.addCircle(0, radius_out, radius_out, Path.Direction.CW);
Path circle2 = new Path();
circle2.addCircle(0, radius_mid - 40, radius_mid - 70, Path.Direction.CW);
Path circle3 = new Path();
circle3.addCircle(0, 0, radius_in, Path.Direction.CW);
seven.setPath(circle3, globalRegion);
Path result = new Path();
result.op(circle1, circle2, Path.Op.DIFFERENCE);
List a = new ArrayList<>();
a.add(circle1);
a.add(result);
a.add(circle3);
return a;
}
画6个扇形:android画圆默认由X轴正方形开始,但是我想让它在Y轴负方法开始,本来打算用旋转canvas来完成,后来发现做点击事件的时候比较繁琐,于是我认为给他加-90度开始达到效果。具体操作看代码,由于第三四个扇形做特殊处理,所以跟之前传进来的path做减法操作。最后把几个path放进Region里面,用来对区域点击处理
/**
* 画六个扇形
*
* @param canvas
* @param paths
* @param bse
*/
private void Paint_sixArc(Canvas canvas, List paths, Path bse) {
int flag = 0;
for (int i = -90; i < 270; i += 60) {
flag++;
Path path1 = new Path();
path1.addArc(new RectF(-radius_mid, -radius_mid, radius_mid, radius_mid), i, 60);
PathMeasure pm = new PathMeasure(path1, false);
float[] pos = new float[2];
pm.getPosTan(0, pos, null);
Path path2 = new Path();
if (i == 90) {
path2.lineTo(0, radius_mid - 50);
} else {
path2.lineTo(pos[0], pos[1]);
}
path1.lineTo(0, 0);
Log.e("-----", "" + (radius_mid * Math.sin(i * unitRadian)) + "," + -(float) (radius_mid * Math.cos(i * unitRadian)));
Paint paint = new Paint();
paint.setColor(getResources().getColor(R.color.white));
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
Paint paint2 = new Paint();
paint2.setColor(getResources().getColor(R.color.gray_out));
paint2.setStyle(Paint.Style.STROKE);
if (i == -30 || i == 150) {
path1.op(paths.get(0), Path.Op.DIFFERENCE);
} else {
path1.op(paths.get(1), Path.Op.DIFFERENCE);
}
path1.op(bse, Path.Op.INTERSECT);
paint2.setAntiAlias(true);
canvas.drawPath(path1, paint);
if (i == -90) {
paint2.setStrokeWidth(10);
} else {
paint2.setStrokeWidth(5);
}
if (i != 30 && i != 150) {
canvas.drawPath(path2, paint2);
}
path1.op(paths.get(2), Path.Op.DIFFERENCE);
canvas.drawPath(paths.get(2), mPaint_center);
switch (flag) {
case 1:
one.setPath(path1, globalRegion);
break;
case 2:
two.setPath(path1, globalRegion);
break;
case 3:
three.setPath(path1, globalRegion);
break;
case 4:
four.setPath(path1, globalRegion);
break;
case 5:
five.setPath(path1, globalRegion);
break;
case 6:
six.setPath(path1, globalRegion);
break;
case 7:
break;
}
}
}
在手指触摸屏幕需要做出反应,因此我重写onTouchEvent方法逻辑基本很简单了,就是判断点击的时候在那个区域然后做出反应。具体请看代码
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float[] pts = {event.getX(), event.getY()};
mMapMatrix.mapPoints(pts);
switch (ifwhere(pts)) {
case "one":
Log.e("--------", ifwhere(pts));
break;
case "two":
Log.e("--------", ifwhere(pts));
break;
case "three":
Log.e("--------", ifwhere(pts));
break;
case "four":
Log.e("--------", ifwhere(pts));
break;
case "five":
Log.e("--------", ifwhere(pts));
break;
case "six":
Log.e("--------", ifwhere(pts));
break;
case "seven":
Log.e("--------", ifwhere(pts));
break;
default:
break;
}
}
return super.onTouchEvent(event);
}
总的来说不是很难(写好当然那么说—,—,但是对于刚开始写的人来说可能很麻烦,我就是啊)就是给新手练练手的。
完整代码下载: 点击打开链接csdn