Android自定义View之渐变色折线图的实现

 更新时间:2022年04月26日 11:41:42   作者:ChenYhong  
折线图的实现方法在github上有很多开源的程序,但是对于初学者来讲,简单一点的教程可能更容易入门,下面这篇文章主要给大家介绍了关于Android自定义View之渐变色折线图的相关资料,需要的朋友可以参考下

前言

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

相关文章

  • Android Studio配置(Android Studio4.1为例)

    Android Studio配置(Android Studio4.1为例)

    这篇文章主要介绍了Android Studio配置(Android Studio4.1为例),文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • Kotlin协程launch原理详解

    Kotlin协程launch原理详解

    这篇文章主要为大家介绍了Kotlin协程launch原理的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Android Handler源码深入探究

    Android Handler源码深入探究

    handler其实就是主线程在起了一个子线程,子线程运行并生成Message,Looper获取message并传递给Handler,Handler逐个获取子线程中的Message
    2022-08-08
  • Jetpack Compose实现动画效果的方法详解

    Jetpack Compose实现动画效果的方法详解

    compose为支持动画提供了大量的 api,通过这些 api 我们可以轻松实现动画效果。本文将为大家介绍利用compose实现的多种动画效果的示例代码,需要的可以参考一下
    2022-02-02
  • Android仿硬币转动微信红包动画效果

    Android仿硬币转动微信红包动画效果

    项目需要研究了一下微信红包动画,即硬币转动的效果,原理其实就是三张不同角度的图片利用AnimationDrawable帧动画进行播放。下面通过本文给大家分享Android仿微信红包动画效果,感兴趣的朋友一起看看吧
    2017-12-12
  • Android协程的7个重要知识点汇总

    Android协程的7个重要知识点汇总

    在现代Android应用开发中,协程(Coroutine)已经成为一种不可或缺的技术,它不仅简化了异步编程,还提供了许多强大的工具和功能,可以在高阶场景中发挥出色的表现,本文将深入探讨Coroutine重要知识点,帮助开发者更好地利用Coroutine来构建高效的Android应用
    2023-09-09
  • Android模拟实现网易新闻客户端

    Android模拟实现网易新闻客户端

    这篇文章主要为大家详细介绍了Android模拟实现网易新闻客户端,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • Android之复选框对话框用法实例分析

    Android之复选框对话框用法实例分析

    这篇文章主要介绍了Android之复选框对话框用法,涉及Android页面布局、对话框类等相关使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-09-09
  • kotlin实现语音聊天机器人案例详解

    kotlin实现语音聊天机器人案例详解

    Android智能问答机器人是时下非常流行的一种服务,微软“小冰”的出现更是让其实实在在的风靡了一把。那么,本文章就将带领大家完整的实现整个问答机器人的制作
    2023-02-02
  • Android屏幕旋转之横屏竖屏切换的实现

    Android屏幕旋转之横屏竖屏切换的实现

    这篇文章主要介绍了Android屏幕旋转之横屏竖屏切换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10

最新评论