Android自定义view绘制鱼骨图

实现效果如下:

自定义view代码如下:

public class MyWidget extends View {
    public MyWidget(Context context) {
        super(context);
    }

    public MyWidget(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyWidget(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MyWidget(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取建议的最小高度
        final int minimumHeight = getSuggestedMinimumHeight();
        //获取建议的最小宽度
        final int minimumWidth = getSuggestedMinimumWidth();
        int width = measureWidth(minimumWidth, widthMeasureSpec);
        int height = measureHeight(minimumHeight, heightMeasureSpec);
        //设置测量的尺寸,用于父布局进行view排列
        setMeasuredDimension(width, height);
    }

    private int measureWidth(int defaultWidth, int measureSpec) {
        //获取测量的模式
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        switch (specMode) {
            case MeasureSpec.AT_MOST://wrap_content
                defaultWidth = /*内容视图大小+*/defaultWidth + getPaddingRight() + getPaddingLeft();
                break;
            case MeasureSpec.EXACTLY://固定值,match_parent
                defaultWidth = specSize;
                break;
            case MeasureSpec.UNSPECIFIED://0dp,空值
                defaultWidth = Math.max(defaultWidth, specSize);
        }
        return defaultWidth;
    }

    private int measureHeight(int defaultHeight, int measureSpec) {
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        switch (specMode) {
            case MeasureSpec.AT_MOST://wrap_content
                defaultHeight = /*内容视图大小+*/defaultHeight + getPaddingTop() + getPaddingBottom();
                break;
            case MeasureSpec.EXACTLY:
                defaultHeight = specSize;
                break;
            case MeasureSpec.UNSPECIFIED://0dp,空值
                defaultHeight = Math.max(defaultHeight, specSize);
                break;
        }
        return defaultHeight;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);
        Paint mPaint = new Paint();
        mPaint.setColor(Color.YELLOW);
        mPaint.setStrokeWidth(3);
        mPaint.setStyle(Paint.Style.STROKE);
        int canvasWidth = getMeasuredWidth();
        int canvasHeight = getMeasuredHeight();
        //图画的中心位置
        int centreY = canvasHeight / 2;
        //绘制一个鱼头
        //计算鱼头的高度
        int fishHeight = canvasHeight - (int) (canvasHeight * 0.1);
        int fishWidth = canvasWidth - (int) (canvasWidth * 0.1);
        Path mHeadPath = new Path();
        //点1
        int x1 = (int) (canvasWidth * 0.8);
        int y1 = centreY - fishHeight / 2;
        mHeadPath.moveTo(x1, y1);

        //点2
        int x2 = canvasWidth - (canvasWidth - fishWidth) / 2;
        int y2 = centreY;
        mHeadPath.lineTo(x2, y2);

        //点3
        int x3 = (int) (canvasWidth * 0.8);
        int y3 = centreY + fishHeight / 2;
        mHeadPath.lineTo(x3, y3);
        mHeadPath.close();
        canvas.drawPath(mHeadPath, mPaint);
        //鱼眼
        int fisheyeWidth = (int) Math.min(fishHeight * 0.06, fishWidth * 0.06);
        int x4 = (int) (x2 - ((x2 - x1) * 0.5));
        x4 = (int) (x1 + ((x4 - x1) * 0.2));
        int y4 = (int) (centreY - fishHeight * 0.25);
        canvas.drawOval(x4, y4, x4 + fisheyeWidth, y4 + fisheyeWidth, mPaint);

        //鱼尾巴
        int x5 = (int) ((canvasWidth - fishWidth) * 0.5);
        int y5 = (int) (centreY - fishHeight * 0.25);
        int stopX = (int) (x5 + fishWidth * 0.1);
        int stopY = centreY;
        canvas.drawLine(x5, y5, stopX, stopY, mPaint);
        int x6 = x5;
        int y6 = (int) (centreY + fishHeight * 0.25);
        canvas.drawLine(x6, y6, stopX, stopY, mPaint);

        //脊梁骨
        int x7 = x3;
        canvas.drawLine(x7, centreY, stopX, centreY, mPaint);
        //鱼骨
        int count = 6;
        //脊梁骨节点宽度
        int mWidth = (x7 - stopX) / count;
        //鱼刺垂直高度
        int y8 = (int) (centreY - fishHeight * 0.5);
        int y9 = (int) (centreY + fishHeight * 0.5);
        for (int index = 0; index < count; index++) {
            int x8 = (int) (mWidth * index) + stopX;
            int stopX8 = x8 + mWidth;
            if (index % 2 == 0) {
                canvas.drawLine(x8, y8, stopX8, centreY, mPaint);
            } else {
                canvas.drawLine(x8, y9, stopX8, centreY, mPaint);
            }
        }
    }
}

通过获取view自身的宽高进行相应的计算,通过直线,椭圆的绘制构成鱼骨图。

发表评论

CAPTCHAis initialing...