前言
在之前的项目中,有做过一个需求,需要实现一个颜色渐变的折线图。当时项目中使用的图表库是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渐变色折线图内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!