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
0
投稿
猜你喜欢
- 本文实例讲述了Android获取SD卡及手机ROM容量的方法。分享给大家供大家参考,具体如下:这里通过一个简单的小例子,来获取SD卡的容量和
- 前言《JAVA打砖块》游戏是自制的游戏。玩家操作一根萤幕上水平的“棒子”,让一颗不断弹来弹去的&am
- 本文实例为大家分享了java实现双色球机选 * 的具体代码,供大家参考,具体内容如下双色球号码1~32不重复选6个(排序好),1~16中
- 随着JDK 14的发布(https://waylau.com/jdk-14-released/),各大Java IDE也开始支持JDK 14
- 这篇文章主要介绍发送验证码和校验验证码的功能,用到一个第三方平台Bmob,那Bmob是什么呢?Bmob可以开发一个云存储的移动应
- 题目描述:给定一 m*n 的矩阵,请按照逆时针螺旋顺序,返回矩阵中所有元素。示例:思路:这是一道典型的模拟问题:我们可以分析一下,遍历前进轨
- 做项目的时候需要对拿到的数据进行“清洗”,比如剔除一些不可能存在的身份证号码。查阅了网上的身份证号码验证算法,自己也总结一下。(一)18身份
- 本文实例讲述了C#使用linq对数组进行筛选排序的方法。分享给大家供大家参考。具体如下:using System;using System.
- 上一篇文章讲解了Spring Cloud 整合 nacos 实现服务注册与发现,nacos除了有服务注册与发现的功能,还有提供动态配置服务的
- 概览Android 平台包含蓝牙网络堆栈支持,此支持能让设备以无线方式与其他蓝牙设备交换数据。应用框架提供通过 Android Blueto
- spring boot实现自动输出word文档功能本文用到Apache POI组件组件依赖在pom.xml文件中添加<dependen
- 1. 内部类很多时候我们创建类的对象的时候并不需要使用很多次,每次只使用一次,这个时候我们就可以使用内部类了1.1 内部类概述内部类就是在一
- 本文采用C#实例讲解了处理图片为浮雕效果的实现方法,这在PS中是一个常见的功能,也是C#中的一个简单的图像处理例子。程序先读取原图,然后依次
- 前言之前因为项目需求,其中使用到了图片的单击显示取消,图片平移缩放功能,昨天突然想再加上图片的旋转功能,在网上看了很多相关的例子,可是没看到
- 前言我们在前面介绍AssignAnalyzer时,对AssignAnalyzer.letInit(DiagnosticPosition, V
- 在你布局或者组件混用的时候你可能会发现 gridview 的九宫格没有完全在页面上显示,只是显示了一个局部(第一行)只有一个滚动条,还不能上
- 简介Java编程的目标是实现现实不能完成的,优化现实能够完成的,是一种虚拟技术。生活中的方方面面都可以虚拟到代码中。代理模式所讲的就是现实生
- 本文实例为大家分享了java实现简单扫雷游戏的具体代码,供大家参考,具体内容如下package com.test.swing;import
- 一、题目描述题目:有五个学生,每个学生有 3 门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成绩),把这些数据存放在磁盘文件 &q
- 一、创建项目1.File->new->project;2.选择“Spring Initializr”,点击next;(jdk1.