自定义view之车辆方向盘

    自己闲着没事练习一下自定义view,就花了一天时间弄了一个方向盘的view,在这里分享给大家:

自定义view之车辆方向盘_第1张图片

    基本实现点击各个区域得到相应回调,界面比较简单,但是对于初学的我来说 花了不少功夫呢,希望对于初学的你来说有些许帮助。

    先说下思路,我是由外向内画,先画外圈,再画内圈,之后画底部图形,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,circle1是一个大轮廓 ,circle2是一个小轮廓,大的path减去小的path,结果保留在result。circle3是中心的蓝色圆path。

    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

你可能感兴趣的:(android,自定义view)