自定义View练习
来源:互联网 发布:淘宝的宝贝网址怎么看 编辑:程序博客网 时间:2024/05/19 19:41
自定义View练习 - 雷达信用图表
练习来源
Android自定义控件 芝麻信用分雷达图
练习的github:https://github.com/alidili/SesameCreditScore
最终效果图
思路
- 绘制多边形
- 绘制连接线
- 绘制填充区域
- 绘制总分数
- 绘制标题和图标
实现过程
0. 定义变量
//数据的数量 private int dataCount; //弧度 private float radian; //多边形的外接圆的半径 private int radius; //中心点x private int centerX; //中心点y private int centerY; private List<CreditBean> creditBeans; //最大分值 public int maxScore; private Paint linePaint; private Paint regionPaint; private Paint totalScorePaint; private Paint titlePaint;
1. 计算点坐标
- 计算坐标的示意图
/** * 获得点坐标 */ public Point getPoint(int index) { return getPoint(index, 1); } /** * 获得点坐标,percent为百分比,用于获得填充区域和文字等的坐标位置. * 坐标的计算是重难点. 可以画图分析. */ public Point getPoint(int index, float percent) { int x = 0; int y = 0; if (index == 0) { x = (int) (centerX + radius * Math.sin(radian) * percent); y = (int) (centerY - radius * Math.cos(radian) * percent); } else if (index == 1) { x = (int) (centerX + radius * Math.sin(radian * 1.0f / 2) * percent); y = (int) (centerY + radius * Math.cos(radian * 1.0f / 2) * percent); } else if (index == 2) { x = (int) (centerX - radius * Math.sin(radian * 1.0f / 2) * percent); y = (int) (centerY + radius * Math.cos(radian * 1.0f / 2) * percent); } else if (index == 3) { x = (int) (centerX - radius * Math.sin(radian) * percent); y = (int) (centerY - radius * Math.cos(radian) * percent); } else if (index == 4) { x = centerX; y = (int) (centerY - radius * percent); } return new Point(x, y); }
2. 绘制过程
@Override protected void onDraw(Canvas canvas) { //绘制多边形 drawPolygon(canvas); //绘制连接线 drawLines(canvas); //绘制填充区域 drawRegion(canvas); //绘制总分数 drawTotalScore(canvas); //绘制标题和图标 drawTitleAndIcons(canvas); }
- 绘制多边形
- 这里注意需要闭合路径
/** * 绘制多边形 */ private void drawPolygon(Canvas canvas) { Path polygonPath = new Path(); for (int i = 0; i < dataCount; i++) { if (i == 0) { polygonPath.moveTo(getPoint(i).x, getPoint(i).y); } else { polygonPath.lineTo(getPoint(i).x, getPoint(i).y); } } polygonPath.close(); canvas.drawPath(polygonPath, linePaint); }
- 绘制连接线
- 直接连线从圆心到各个顶点
/** * 绘制连接线 */ private void drawLines(Canvas canvas) { for (int i = 0; i < dataCount; i++) { canvas.drawLine(centerX, centerY, getPoint(i).x, getPoint(i).y, linePaint); } }
- 绘制填充区域
- 这里的获得百分比坐标的方式可以注意下.
/** * 绘制填充区域 */ private void drawRegion(Canvas canvas) { Path regionPath = new Path(); float percent; for (int i = 0; i < creditBeans.size(); i++) { percent = creditBeans.get(i).score * 1.0f / maxScore; int x = getPoint(i, percent).x; int y = getPoint(i, percent).y; if (i == 0) { regionPath.moveTo(x, y); } else { regionPath.lineTo(x, y); } } regionPath.close(); canvas.drawPath(regionPath, regionPaint); }
- 绘制总分数
- 总分数的文字绘制在正中心.
- 这里要注意文字的宽度和高度的获得方式.
/** * 绘制总分数 */ private void drawTotalScore(Canvas canvas) { int totalScore = 0; for (CreditBean creditBean : creditBeans) { totalScore += creditBean.score; } //获得文字宽度 float textWidth = totalScorePaint.measureText(String.valueOf(totalScore)); Paint.FontMetrics fontMetrics = totalScorePaint.getFontMetrics(); //获得文字高度 float textHeight = Math.abs(fontMetrics.ascent) - fontMetrics.descent; canvas.drawText(String.valueOf(totalScore), centerX - textWidth / 2, centerY + textHeight / 2, totalScorePaint); }
- 绘制标题和图标
- 图标和文字位置是根据文字和图标的宽高计算的.
/** * 绘制标题和图标 */ private void drawTitleAndIcons(Canvas canvas) { for (int i = 0; i < creditBeans.size(); i++) { String title = creditBeans.get(i).title; int textX = getPoint(i, 1.2f).x; int textY = getPoint(i, 1.2f).y; //获得文字的宽高 int textWidth = (int) titlePaint.measureText(title); Paint.FontMetrics fontMetrics = titlePaint.getFontMetrics(); int textHeight = (int) (Math.abs(fontMetrics.ascent) - fontMetrics.descent); //获得图标的宽高 Bitmap icon = BitmapFactory.decodeResource(getResources(), creditBeans.get(i).icon); int iconWidth = icon.getWidth(); int iconHeight = icon.getHeight(); if (i == 0) { //不需要修正位置 } else if (i == 1) { textY += textHeight; } else if (i == 2) { textX -= textWidth; textY += textHeight; } else if (i == 3) { textX -= textWidth; } else { textX -= textWidth / 2; } int iconX = textX + textWidth / 2 - iconWidth / 2; int iconY = textY - textHeight - iconHeight - DensityUtils.dp2px(getContext(), 8); canvas.drawText(title, textX, textY, titlePaint); canvas.drawBitmap(icon, iconX, iconY, null); } }
3. 设置数据
/** * 设置数据 */ public void setData(List<CreditBean> creditBeans, int maxScore) { this.creditBeans = creditBeans; this.dataCount = creditBeans.size(); this.maxScore = maxScore; this.radian = (float) (Math.PI * 2 * 1.0f / dataCount); }
学到的知识
- 文字的宽度和高度的获得
//获得文字宽度 float textWidth = totalScorePaint.measureText(String.valueOf(totalScore)); //获得文字高度 Paint.FontMetrics fontMetrics = totalScorePaint.getFontMetrics(); float textHeight = Math.abs(fontMetrics.ascent) - fontMetrics.descent;
- 获得多边形每个顶点的位置, 坐标的计算是个重点.
注意: Math.sin() 参数是弧度. 如果需要将角度转为弧度, 可以使用Math.toRadian(). - 计算填充区域顶点坐标和多边形的顶点是在同一条过圆心的直线上. 这里使用了percent来获得两个坐标.
/** * 获得点坐标 */ public Point getPoint(int index) { return getPoint(index, 1); } /** * 获得点坐标,percent为百分比,用于获得填充区域和文字等的坐标位置. */ public Point getPoint(int index, float percent) { int x = 0; int y = 0; if (index == 0) { x = (int) (centerX + radius * Math.sin(radian) * percent); y = (int) (centerY - radius * Math.cos(radian) * percent); } else if (index == 1) { x = (int) (centerX + radius * Math.sin(radian * 1.0f / 2) * percent); y = (int) (centerY + radius * Math.cos(radian * 1.0f / 2) * percent); } else if (index == 2) { x = (int) (centerX - radius * Math.sin(radian * 1.0f / 2) * percent); y = (int) (centerY + radius * Math.cos(radian * 1.0f / 2) * percent); } else if (index == 3) { x = (int) (centerX - radius * Math.sin(radian) * percent); y = (int) (centerY - radius * Math.cos(radian) * percent); } else if (index == 4) { x = centerX; y = (int) (centerY - radius * percent); } return new Point(x, y); }
github地址:
阅读全文
0 0
- 自定义View小练习
- 自定义View练习
- 自定义View练习
- 自定义View练习
- 自定义View练习
- 自定义View练习
- 自定义View练习一
- 自定义view-canvas练习
- 自定义View练习1
- 自定义View练习2
- android自定义View练习之波浪View
- Android 自定义View练习之水波纹
- 自定义 view 练习(2):卫星式菜单
- 自定义View练习(一)饼状图
- 自定义View练习(二)二阶贝塞尔曲线
- HenCoder 自定义 View 1-1 练习项目
- 新手自定义view练习实例之(二) 波浪view
- 自定义View练习(一个自定义的折线图)
- Ext JS 6学习文档–第2章–核心概念
- javascript作用域与闭包
- ZOJ--1002:Fire_Net
- 关于博客背景
- AndroidSDK 环境搭建
- 自定义View练习
- 域名解析到部署出现的问题总结
- UVA-796(无向图割桥模板题)
- Android控件
- Python-First day
- jumpserver 简单使用
- hibernate-hql-18
- 名企笔试:美团2016招聘笔试(股票交易日)
- MSSQL:用opendatasource增删改查ACCESS