Android自定义View之渐变色折线图的实现
短信预约 -IT技能 免费直播动态提醒
前言
在之前的项目中,有做过一个需求,需要实现一个颜色渐变的折线图。当时项目中使用的图表库是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>
效果如下图:
总结
到此这篇关于Android自定义View之渐变色折线图的文章就介绍到这了,更多相关Android渐变色折线图内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341