Android 自定义View之能力分析图

在这里插入图片描述

MainActivity

        //能力分析图
        AbilityAnalysisView abilityView = (AbilityAnalysisView) findViewById(R.id.abilityAnalysisView_id)
        analysisView.setDataCount(5)
                    .setTitles(new String[]{"伤害", "防御", "攻速", "吸血", "助攻"})
                    .setDatas(new float[]{170, 120, 90, 210, 120})//TODO 赋值相应的各维度分值,数据最大值maxValue在自定义View里可以更改
                    .setColors(new  int[]{R.color.colorOrange4, R.color.colorOrange3, R.color.colorOrange2, R.color.colorOrange1, R.color.colorOrange5})
                    .invalidate();//TODO 坑更新自定义View 调用OnDraw方法

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000000">

    <com.reachauto.abilityanalysis.AbilityAnalysisView
        android:id="@+id/abilityAnalysisView_id"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true" />

</RelativeLayout>

AbilityAnalysisView

public class AbilityAnalysisView extends View {

    //数据个数
    private int dataCount = 5;
    //每个角的弧度
    private float radian = (float) (Math.PI * 2 / dataCount);
    //雷达图半径
    private float radius;
    //中心X坐标
    private int centerX;
    //中心Y坐标
    private int centerY;
    //各维度标题
    private String[] titles = {"伤害", "防御", "攻速", "吸血", "助攻"};
    private int[] colors = {R.color.colorOrange4, R.color.colorOrange3, R.color.colorOrange2, R.color.colorOrange1, R.color.colorOrange5};
    //各维度图标
  //  private int[] icons = {R.mipmap.ic_performance, R.mipmap.ic_history, R.mipmap.ic_contacts,
  //          R.mipmap.ic_predilection, R.mipmap.ic_identity};
    //各维度分值
    private float[] data = {170, 120, 90, 210, 150};
    //数据最大值
    private float maxValue = 210;
    //雷达图与标题的间距
    private int radarMargin = DensityUtils.dp2px(getContext(), 15);
    //雷达区画笔
    private Paint mainPaint;
    //数据区画笔
    private Paint valuePaint;
    //分数画笔
    private Paint scorePaint;
    //标题画笔
    private Paint titlePaint;
    //图标画笔
    private Paint iconPaint;
    //分数大小
    private int scoreSize = DensityUtils.dp2px(getContext(), 28);
    //标题文字大小
    private int titleSize = DensityUtils.dp2px(getContext(), 13);


    public AbilityAnalysisView(Context context) {
        this(context, null);
    }

    public AbilityAnalysisView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public AbilityAnalysisView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mainPaint = new Paint();
        mainPaint.setAntiAlias(true);
        mainPaint.setStrokeWidth(0.3f);
        mainPaint.setColor(Color.WHITE);
        mainPaint.setStyle(Paint.Style.STROKE);

        valuePaint = new Paint();
        valuePaint.setAntiAlias(true);
        valuePaint.setColor(Color.WHITE);
        valuePaint.setAlpha(120);
        valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);


        scorePaint = new Paint();
        scorePaint.setAntiAlias(true);
        scorePaint.setTextSize(scoreSize);
        scorePaint.setColor(Color.WHITE);
        scorePaint.setTextAlign(Paint.Align.CENTER);
        scorePaint.setStyle(Paint.Style.FILL);

        titlePaint = new Paint();
        titlePaint.setAntiAlias(true);
        titlePaint.setTextSize(titleSize);
        titlePaint.setColor(Color.WHITE);
        titlePaint.setStyle(Paint.Style.FILL);

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        //雷达图半径
        radius = Math.min(h, w) / 2 * 0.5f;
        //中心坐标
        centerX = w / 2;
        centerY = h / 2;
        postInvalidate();
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        drawPolygon(canvas);
     //   drawLines(canvas);
        drawRegion(canvas, colors);
        drawScore(canvas);
        drawTitle(canvas);
    }


    /**
     * 绘制多边形
     *
     * @param canvas 画布
     */
    private void drawPolygon(Canvas canvas) {
        Path path = new Path();
//        for (int i = 0; i < dataCount; i++) {
//            if (i == 0) {
//                path.moveTo(getPoint(i).x, getPoint(i).y);
//            } else {
//                path.lineTo(getPoint(i).x, getPoint(i).y);
//            }
//        }
//
//        //闭合路径
//        path.close();
//        canvas.drawPath(path, mainPaint);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(7);
        paint.setColor(getResources().getColor(R.color.colorGray));
        paint.setStyle(Paint.Style.STROKE);

        canvas.drawCircle(centerX,centerY,radius,paint);
        paint.setStrokeWidth(3);
        canvas.drawCircle(centerX,centerY,(radius * 9)/10, paint);
        canvas.drawCircle(centerX,centerY,(radius * 8)/10, paint);
        canvas.drawCircle(centerX,centerY,(radius * 7)/10, paint);
    }

    /**
     * 绘制连接线
     *
     * @param canvas 画布
     */
    private void drawLines(Canvas canvas) {
        Path path = new Path();
        for (int i = 0; i < dataCount; i++) {
            path.reset();
            path.moveTo(centerX, centerY);
            path.lineTo(getPoint(i).x, getPoint(i).y);
            canvas.drawPath(path, mainPaint);

        }

    }
    /**
     * 获取雷达图上各个点的坐标
     *
     * @param position 坐标位置(右上角为0,顺时针递增)
     * @return 坐标
     */
    private Point getPoint(int position) {
        return getPoint(position, 0, 1);
    }

    /**
     * 获取雷达图上各个点的坐标(包括维度标题与图标的坐标)
     *
     * @param position    坐标位置
     * @param radarMargin 雷达图与维度标题的间距
     * @param percent     覆盖区的的百分比
     * @return 坐标
     */
    private Point getPoint(int position, int radarMargin, float percent) {
        int x = 0;
        int y = 0;

        if (position == 0) {
            x = (int) (centerX + (radius + radarMargin) * Math.sin(radian) * percent);
            y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent);

        } else if (position == 1) {
            x = (int) (centerX + (radius + radarMargin) * Math.sin(radian / 2) * percent);
            y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent);

        } else if (position == 2) {
            x = (int) (centerX - (radius + radarMargin) * Math.sin(radian / 2) * percent);
            y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent);

        } else if (position == 3) {
            x = (int) (centerX - (radius + radarMargin) * Math.sin(radian) * percent);
            y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent);

        } else if (position == 4) {
            x = centerX;
            y = (int) (centerY - (radius + radarMargin) * percent);
        }

        return new Point(x, y);
    }

    /**
     * 绘制覆盖区域
     *
     * @param canvas 画布
     */
    private void drawRegion(Canvas canvas, int[] colors) {


        for (int i = 0; i < dataCount; ++i) {
            Path path = new Path();
            path.moveTo(centerX, centerY);
            //计算百分比
            float percent = data[i] / maxValue;
            int x = getPoint(i, 0, percent).x;
            int y = getPoint(i, 0, percent).y;
            path.lineTo(x, y);
            //计算百分比
            if (dataCount == i+ 1){
                float percent_next = data[0] / maxValue;
                int x_next = getPoint(0, 0, percent_next).x;
                int y_next = getPoint(0, 0, percent_next).y;
                path.lineTo(x_next, y_next);
                path.lineTo(centerX, centerX);
            }else {
                float percent_next = data[i + 1] / maxValue;
                int x_next = getPoint(i+1, 0, percent_next).x;
                int y_next = getPoint(i+1, 0, percent_next).y;
                path.lineTo(x_next, y_next);
                path.lineTo(centerX, centerX);
            }

            valuePaint.setColor(getResources().getColor(colors[i]));

            path.close();
           //绘制填充区域的边界
            valuePaint.setStyle(Paint.Style.STROKE);
            canvas.drawPath(path, valuePaint);

            //绘制填充区域
            valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);
            canvas.drawPath(path, valuePaint);
        }

    }

    private void drawRegion1(Canvas canvas) {
        Path path = new Path();

        for (int i = 0; i < dataCount; i++) {
            //计算百分比
            float percent = data[i] / maxValue;
            int x = getPoint(i, 0, percent).x;
            int y = getPoint(i, 0, percent).y;
            if (i == 0) {
                path.moveTo(x, y);
            } else {
                path.lineTo(x, y);
            }
        }
        //绘制填充区域的边界
        path.close();
        valuePaint.setStyle(Paint.Style.STROKE);
        canvas.drawPath(path, valuePaint);

        //绘制填充区域
        valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawPath(path, valuePaint);
    }

    /**
     * 绘制标题
     *
     * @param canvas 画布
     */
    private void drawTitle(Canvas canvas) {
        for (int i = 0; i < dataCount; i++) {
            int x = getPoint(i, radarMargin, 1).x;
            int y = getPoint(i, radarMargin, 1).y;

         //   Bitmap bitmap = BitmapFactory.decodeResource(getResources(), icons[i]);
          //  int iconHeight = bitmap.getHeight();
            int iconHeight = 20;
            float titleWidth = titlePaint.measureText(titles[i]);

            //底下两个角的坐标需要向下移动半个图片的位置(1、2)
            if (i == 1) {
                y += (iconHeight / 2);
            } else if (i == 2) {
                x -= titleWidth;
                y += (iconHeight / 2);
            } else if (i == 3) {
                x -= titleWidth;
            } else if (i == 4) {
                x -= titleWidth / 2;
            }
            canvas.drawText(titles[i], x, y, titlePaint);
        }
    }

    /**
     * 绘制分数
     *
     * @param canvas 画布
     */
    private void drawScore(Canvas canvas) {
        int score = 0;
        //计算总分
        for (int i = 0; i < dataCount; i++) {
            score += data[i];
        }
        canvas.drawText(score + "", centerX, centerY + scoreSize / 2, scorePaint);
    }

    public int[] getColors(){
        return colors;
    }

    public AbilityAnalysisView setColors(int[] colors){
        this.colors = colors;
        return this;
    }

    public String[] getTitles() {
        return titles;
    }

    public AbilityAnalysisView setTitles(String[] titles) {
        if (titles == null || titles.length < dataCount) {
            throw new IllegalArgumentException("titles size can't be less than " + dataCount);
        }
        for (int i = 0; i < titles.length; i++) {
            if (StringUtil.notEmpty(titles[i]).equals("N/A")) {
                throw new IllegalArgumentException("value in titles can't be null or empty");
            }
        }
        this.titles = titles;
        return this;
    }

    public int getDataCount() {
        return dataCount;
    }

    public AbilityAnalysisView setDataCount(int dataCount) {
        if (dataCount < 3) {
            throw new IllegalArgumentException("Edge of polygon can't be less than three");
        }
        dataCount = dataCount;
        return this;
    }

    public float[] getDatas() {
        return data;
    }

    public AbilityAnalysisView setDatas(float[] datas) {
        if (datas == null || datas.length < dataCount) {
            throw new IllegalArgumentException("datas size can't be less than " + dataCount);
        }
        this.data = datas;
        return this;
    }


}

DensityUtils

/**
 * px与dp互相转换
 * Created by yangle on 2016/4/12.
 */
public class DensityUtils {
    public static int dp2px(Context context, float dp) {
        //获取设备密度
        float density = context.getResources().getDisplayMetrics().density;
        //4.3, 4.9, 加0.5是为了四舍五入
        int px = (int) (dp * density + 0.5f);
        return px;
    }

    public static float px2dp(Context context, int px) {
        //获取设备密度
        float density = context.getResources().getDisplayMetrics().density;
        float dp = px / density;
        return dp;
    }
}

StringUtill

/**
 * 空值判断
 */
public class StringUtil {
    public static String notEmpty(String value) {
        if (value != null && !TextUtils.isEmpty(value) && !TextUtils.isEmpty(value.trim())) {
            return value;
        }
        return "N/A";
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Allen.Su

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值