Android自定义View之渐变色折线图的实现
作者:ChenYhong 发布时间:2023-09-23 21:43:03
标签:android,渐变色,折线图
前言
在之前的项目中,有做过一个需求,需要实现一个颜色渐变的折线图。当时项目中使用的图表库是MPAndroidChart,但是该库没有提供合适的方法来实现想要的效果,因此只能通过自定义view来实现。
通过这篇文章记录一下,便于之后需要实现类似的效果时查找使用。
如何实现
通过创建LinearGradient来实现颜色渐变,并将之设置到画笔Paint的着色器Shader,绘制想要的路径即可实现该效果。
实现代码如下:
class GradientLineChart : View {
private var viewWidth: Int = 0
private var viewHeight: Int = 0
private var chartWidth: Int = 0
private var chartHeight: Int = 0
/**
* 折线宽度
*/
private var lineWidth: Float = 0f
/**
* 网格线宽度
*/
private var gridLineWidth: Float = 0f
/**
* 网格线颜色
*/
private var gridLineColor: Int = 0
/**
* 背景颜色
*/
private var backgroundColorRes: Int = 0
private var linePaint: Paint? = null
private var gridLinePaint: Paint? = null
private var gradientColor: IntArray? = null
private val rectF = RectF()
private val linePath = Path()
private val lineValueList = ArrayList<LineEntity>()
constructor(context: Context?) : this(context, null)
constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
lineValueList.add(LineEntity(3f, 28f))
lineValueList.add(LineEntity(7f, 2f))
lineValueList.add(LineEntity(14f, 18f))
lineValueList.add(LineEntity(17f, 12f))
lineValueList.add(LineEntity(22f, 21f))
context?.let {
gradientColor = intArrayOf(
ContextCompat.getColor(it, R.color.color_FFD200),
ContextCompat.getColor(it, R.color.color_FF2600),
ContextCompat.getColor(it, R.color.color_49E284),
ContextCompat.getColor(it, R.color.color_00A5FF)
)
}
initAttr(attrs, defStyleAttr)
initPaint()
}
private fun initAttr(attrs: AttributeSet?, defStyleAttr: Int) {
val typeArray =
context.theme.obtainStyledAttributes(attrs, R.styleable.GradientLineChart, defStyleAttr, 0)
lineWidth = typeArray.getDimension(
R.styleable.GradientLineChart_tc_lineWidth,
DensityUtil.dp2Px(2).toFloat()
)
gridLineWidth = typeArray.getDimension(
R.styleable.GradientLineChart_tc_grid_line_width,
DensityUtil.dp2Px(1).toFloat()
)
gridLineColor = typeArray.getColor(
R.styleable.GradientLineChart_tc_grid_line_color,
ContextCompat.getColor(context, R.color.color_1Affffff)
)
backgroundColorRes = typeArray.getColor(
R.styleable.GradientLineChart_tc_background_color,
ContextCompat.getColor(context, R.color.color_23242a)
)
typeArray.recycle()
}
private fun initPaint() {
linePaint = Paint()
linePaint?.isAntiAlias = true
linePaint?.style = Paint.Style.STROKE
linePaint?.strokeWidth = lineWidth
gridLinePaint = Paint()
gridLinePaint?.isAntiAlias = true
gridLinePaint?.style = Paint.Style.FILL
gridLinePaint?.color = gridLineColor
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
viewWidth = MeasureSpec.getSize(widthMeasureSpec)
viewHeight = MeasureSpec.getSize(heightMeasureSpec)
//MUST CALL THIS
setMeasuredDimension(viewWidth, viewHeight)
chartWidth = viewWidth - paddingStart - paddingEnd
chartHeight = viewHeight - paddingTop - paddingBottom
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
//设置画布背景色
canvas?.drawColor(backgroundColorRes)
//绘制网格线
drawGradLine(canvas)
//绘制折线
drawLine(canvas)
}
/**
* 绘制网格线
*/
private fun drawGradLine(canvas: Canvas?) {
gridLinePaint?.let {
val yGridValues = 7
val xGridValues = 6
//Y轴网格线间距
val yGridDistance = (chartHeight - yGridValues * gridLineWidth) / (yGridValues - 1)
for (index in 0 until yGridValues) {
val left = paddingStart.toFloat()
val top = paddingTop.toFloat() + index * yGridDistance + index * gridLineWidth
val right = left + chartWidth
val bottom = top + gridLineWidth
rectF.set(left, top, right, bottom)
canvas?.drawRect(rectF, it)
}
//X轴网格线间距
val xGridDistance = (chartWidth - xGridValues * gridLineWidth) / (xGridValues - 1)
for (index in 0 until xGridValues) {
val left = paddingStart + xGridDistance * index + gridLineWidth * index
val top = paddingTop.toFloat()
val right = left + gridLineWidth
val bottom = top + chartHeight
rectF.set(left, top, right, bottom)
canvas?.drawRect(rectF, gridLinePaint!!)
}
}
}
/**
* 绘制折线
*/
private fun drawLine(canvas: Canvas?) {
val yGridValues = 7
val xGridValues = 6
val yGridDistance = (chartHeight - yGridValues * gridLineWidth) / (yGridValues - 1)
val xGridDistance = (chartWidth - xGridValues * gridLineWidth) / (xGridValues - 1)
for ((index, linePoint) in lineValueList.withIndex()) {
val pointX =
((linePoint.xValue - 5 * index) / 5) * xGridDistance + (xGridDistance * index)
val pointY =
chartHeight - (linePoint.yValue / 30 * (yGridDistance * 6))
if (index == 0) {
linePath.moveTo(pointX, pointY)
} else {
linePath.lineTo(pointX, pointY)
}
}
linePaint?.shader = createLineGradient(gradientColor!!)
canvas?.drawPath(linePath, linePaint!!)
}
private fun createLineGradient(gradientColor: IntArray): LinearGradient {
return LinearGradient(
0f,
0f,
0f,
viewHeight.toFloat(),
gradientColor,
null,
Shader.TileMode.CLAMP
)
}
}
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="GradientLineChart">
<!--线宽度-->
<attr name="tc_lineWidth" format="dimension" />
<!--网格线宽度-->
<attr name="tc_grid_line_width" format="dimension" />
<!--网格线颜色-->
<attr name="tc_grid_line_color" format="color" />
<!--等级颜色指示器宽度-->
<attr name="tc_level_indicator_width" format="dimension" />
<!--背景颜色-->
<attr name="tc_background_color" format="color" />
</declare-styleable>
</resources>
效果如下图:
来源:https://juejin.cn/post/7089705458532876296


猜你喜欢
- Android 获取屏幕尺寸实例代码实现代码:/** * <supports-screens * android:smallScr
- 一、前言Android 实现卫星式菜单也叫弧形菜单,主要要做的工作如下:1.动画的处理2.自定义ViewGroup来实现卫星式菜单View(
- java类型转换 Integer String Long Float Double Date1如何将字串 String 转换成整数 int?
- 相信很多人在读取文件的时候都会碰到乱码的情况,所谓乱码就是错乱的编码的意思,造成乱码的是由于编码不一致导致的。演示程序:新建3个文本文件:编
- 本文实例讲述了C#中图片、二进制与字符串的相互转换方法。分享给大家供大家参考,具体如下:protected void Button1_Cli
- 工具类-java精确到小数点后6位验证要求,必须精确到小数点后6位,但是后面都是0的话,double会省略0,正则验证不通过,所以有了下面解
- 在IntelliJ IDEA中一不小心将你本地代码给覆盖了,这个时候,你 ctrl + z
- 现公司架构大佬在项目中使用了 mybatis-generator-gui ,这是一款开源图形化 MyBatis 代码生成工具,使用起来相当的
- 类和对象的关系类就是一类对象的统称。对象就是这一类具体化的一个实例。 (对象是类的实例化)对象是什么?此对象非彼对象!!!😂说到对象就要提到
- 在 Spring Boot 中做权限管理,一般来说,主流的方案是 Spring Security ,但是,仅仅从技术角度来说,也可以使用 S
- 本文实例讲述了Java Swing组件编程之JTable表格用法。分享给大家供大家参考,具体如下:表格是GUI编程中使用较多,但也是最麻烦的
- 1. 需求描述有这样一个需求,用ViewPager实现图片滑动,其下方有一个tab,每一个tab的标签对应一组图片,在ViewPager中的
- 本文实例为大家分享了SpringMVC使用MultipartFile实现文件上传的具体代码,供大家参考,具体内容如下一、配置文件Spring
- 引入pom<?xml version="1.0" encoding="UTF-8"?>&
- ResultSet 动态获取列名和值仅供自己方便查阅,无其他用途ResultSet result = null; //前边SQL查询结果,这
- 代码很简单,功能也很简单,这里就不多废话了#include<stdio.h>int main(){ char ku[16]={&
- 面向方面编程(Aspect Oriented Programming,简称AOP)是一种声明式编程(Declarative Programm
- 这篇文章主要介绍了JAVA利用递归删除文件代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可
- 过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来
- 本文适合有 Java 基础的人群作者:DJL-LankingHelloGitHub 推出的《讲解开源项目》系列。有幸邀请到了亚马逊 + Ap