Android 自定义View(画线循迹,雷达图+动画实现)

自定义首先接触到的时候觉得很有兴趣,便学习了一下




学习完以上的教程后,还是需要自己动手来实践一下。

1.画线循迹

  • 1.画出轨迹 :
    先试着完成一个触控画线的功能,就是在屏幕上触控画线,画线需要一个Paint个一个Path,然后还要重写onToucheEvent()记录移动的位置,再连线即可。
    onTouchEvent()
public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //设置起始点
                mStartX = event.getX();
                mStartY = event.getY();
                //清空原有的轨道
                mMovePath.reset();
                //移动到起始点
                mMovePath.moveTo(mStartX, mStartY);
                return true;
            case MotionEvent.ACTION_MOVE:
                final float endX = (mStartX + event.getX()) / 2;
                final float endY = (mStartY + event.getY()) / 2;
                //画出轨道曲线,quad是二次曲线
                mMovePath.quadTo(mStartX, mStartY, endX, endY);
                mStartX = event.getX();
                mStartY = event.getY();
                //重绘
                invalidate();
                return true;
        }
        return super.onTouchEvent(event);
    }

然后在onDraw()中调用drawPath()即可。

  • 2.跟随轨迹移动
private void drawMove(Canvas canvas) {
        pathMeasure.setPath(mMovePath, false);
        if (isMove) {
            //计算图片的旋转角度,tan是当前点切线值,根据切线值计算角度
            float degree = (float) (Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI);
            //旋转对应的角度
            canvas.rotate(degree, pos[0], pos[1]);
            //设置中心点在运行轨道上
            mRect.set(pos[0] - mRectWidth, pos[1] - mRectWidth, pos[0] + mRectWidth, pos[1] + mRectWidth);
            //绘制draw
            if (mDrawable == null) {
                canvas.drawRect(mRect, mCarPaint);
            } else {
                canvas.drawBitmap(mBitmap, null, mRect, mPaint);
            }
        }
    }

在这里插入图片描述

随意画一条轨道。点击启动开始动画
在这里插入图片描述
正确的完成了轨道。

具体参考Github:DiyViewPracticeDemo

2.雷达图

雷达图的绘制我分为三部分,雷达网的绘制,覆盖区域的绘制,边界文字描述绘制
雷达网的绘制

	/**
     * 绘制雷达图。
     */
    private void drawRader(Canvas canvas) {
        radarPaint.setPathEffect(null);
        float gap = radius / (dataCount - 1);
        //雷达网的绘制
        for (int i = 1; i < dataCount; i++) {
            //不同环的半径,dataCount-1个环
            float currentR = gap * i;
            radarPath.reset();
            for (int j = 0; j < dataCount; j++) {
                //如果是0,也就移到右边的起始点
                if (j == 0) {
                    radarPath.moveTo(centerX + currentR, centerY);
                } else {
                    //其他情况得到60°,120°,180°,240°,300°的cos和sin值,利用cos值得到x轴坐标,sin值得到y轴坐标。
                    radarPath.lineTo((float) (centerX + currentR * Math.cos(angle * j)), (float) (centerY + currentR * Math.sin(angle * j)));
                }
            }
            //闭合,终点连上起点
            radarPath.close();
            canvas.drawPath(radarPath, radarPaint);
        }

        //绘制中心到边界点的虚线
        radarPaint.setPathEffect(dashPathEffect);
        for (int i = 0; i < dataCount; i++) {
            radarPath.reset();
            radarPath.moveTo(centerX, centerY);
            radarPath.lineTo((float) (centerX + radius * Math.cos(angle * i)), (float) (centerY + radius * Math.sin(angle * i)));
            canvas.drawPath(radarPath, radarPaint);
        }
    }

覆盖区域绘制

//绘制覆盖区域
    private void drawRegion(Canvas canvas) {
        int sum = 0;
        for (int i = 0; i < dataCount; i++) {
            double percent = drawed[i] / MAX_Value;
            sum += drawed[i];

            //得到对应分值的对应的x,y坐标
            float x = (float) (centerX + radius * Math.cos(angle * i) * percent);
            float y = (float) (centerY + radius * Math.sin(angle * i) * percent);

            //绘制过程同雷达网的绘制过程
            if (i == 0) {
                regionPath.moveTo(x, centerY);
            } else {
                regionPath.lineTo(x, y);
            }

            //为边界点绘制小圆点
            canvas.drawCircle(x, y, 5, valuePaint);
        }
        //闭合
        regionPath.close();
        canvas.drawPath(regionPath, valuePaint);

        valuePaint.setAlpha(255 / 2);
        valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawPath(regionPath, valuePaint);

        canvas.save();
        String centerText = "能力值:%d";
        canvas.drawText(String.format(Locale.getDefault(), centerText, sum), centerX - centerTextPaint.measureText(centerText) / 2, centerY, centerTextPaint);
        canvas.restore();
    }

边界文字描述绘制

//绘制边界点的文字描述
    private void drawText(Canvas canvas) {
        float fontBaseLine = fontMetrics.descent - fontMetrics.ascent;
        for (int i = 0; i < dataCount; i++) {
            //x,y也就是边界点的坐标
            float x = (float) (centerX + (radius + fontBaseLine / 2) * Math.cos(angle * i));
            float y = (float) (centerY + (radius + fontBaseLine / 2) * Math.sin(angle * i));

            //位于左边的需要左移文字长度大小
            if (angle * i >= 0 && angle * i < Math.PI / 2) {//0°<=角度<90°
                canvas.drawText(strings[i], x, y, textPaint);
            } else if (angle * i >= Math.PI / 2 && angle * i < Math.PI) {//90°<=角度<180°
                float dis = textPaint.measureText(strings[i]);//文本长度
                canvas.drawText(strings[i], x - dis, y, textPaint);
            } else if (angle * i >= Math.PI && angle * i < 3 * Math.PI / 2) {//180°<=角度<270°
                float dis = textPaint.measureText(strings[i]);//文本长度
                canvas.drawText(strings[i], x - dis, y, textPaint);
            } else if (angle * i >= 3 * Math.PI / 2 && angle * i < Math.PI * 2) {//270°<=角度<=360°
                canvas.drawText(strings[i], x, y, textPaint);
            }
        }
    }

效果如下图:

具体参考Github:DiyViewPracticeDemo

发布了38 篇原创文章 · 获赞 6 · 访问量 3389

猜你喜欢

转载自blog.csdn.net/qq_37704124/article/details/101019677