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渐变色折线图内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android 自定义圆形带刻度渐变色的进度条样式实例代码

    效果图 一.绘制圆环 圆环故名思意,第一个首先绘制是圆环 1:圆环绘制函数 圆环API public void drawArc (RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) 参数说明 oval:圆弧所在的椭圆对象. startAngle:圆弧的起始角度. sweepAngle:圆弧的角度. useCenter:是否显示半径连线,true表示显示圆弧与圆心的半径连线,false表示不

  • Android实现渐变色的圆弧虚线效果

    首先来看看效果图: 1,SweepGradient(梯度渲染) public SweepGradient (float cx, float cy, int[] colors, float[] positions) 扫描渲染,就是以某个点位中心旋转一周所形成的效果!参数依次是: cx:扫描的中心x坐标 cy:扫描的中心y坐标 colors:梯度渐变的颜色数组 positions:指定颜色数组的相对位置 public static final int[] SWEEP_GRADIENT_COLORS

  • Android自定义控件实现折线图

    本文实例实现一个如下图所示的Android折线图,供大家参考,具体内容如下 首先是控件绘图区域的划分,控件左边取一小部分(控件总宽度的八分之一)绘制表头,右边剩余的部分绘制表格 确定表格的行列数,首先绘制一个三行八列的网格,设置好行列的坐标后开始绘制 /*绘制三条横线*/ for(int i=0;i<3;i++){ canvas.drawLine(textWide, mLineYs[i], totalWidth, mLineYs[i], mPaintLine); } /*绘制八条竖线*/ for

  • android自定义进度条渐变色View的实例代码

    最近在公司,项目不是很忙了,偶尔看见一个兄台在CSDN求助,帮忙要一个自定义的渐变色进度条,我当时看了一下进度条,感觉挺漂亮的,就尝试的去自定义view实现了一个,废话不说,先上图吧! 这个自定义的view,完全脱离了android自带的ProgressView,并且没使用一张图片,这样就能更好的降低程序代码上的耦合性! 下面我贴出代码  ,大概讲解一下实现思路吧! 复制代码 代码如下: package com.spring.progressview; import android.conten

  • Android绘制动态折线图

    所谓动态折线图,就是折线图能随着手指的滑动进行动态绘制,这里很定会产生动画效果.基于这个效果,这里使用SurfaceView进行制图. 实现步奏如下: (1): 这里新建一个绘图ChartView,继承SurfaceView并实现SurfaceHolder.Callback , Runnable接口,主要绘图工作在子线程中完成. (2):现实 SurfaceHolder.Callback接口的三个方法,并在 surfaceCreated中开启子线程进行绘图. (3):重写onTouchEvent

  • Android自定义View实现渐变色进度条

    在网上看到一个进度条效果图,非常美观,如下: 进行效果分解: 1.渐变色,看起来颜色变化并不复杂,使用LinearGradient应该可以实现. 2.圆头,无非是画两个圆,外圆使用渐变色的颜色,内圆固定为白色. 3.灰底,还没有走到的进度部分为灰色. 4.进度值,使用文本来显示: 5.弧形的头部,考虑使用直线进行连接,或者使用曲线,例如贝塞尔曲线: 我首先初步实现了进度条的模样,发现样子有了,却不太美观. 反思了一下,我只是个写代码的,对于哪种比例比较美观,是没有清晰的认识的,所以,还是参考原图

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

    目录 前言 如何实现 总结 前言 在之前的项目中,有做过一个需求,需要实现一个颜色渐变的折线图.当时项目中使用的图表库是MPAndroidChart,但是该库没有提供合适的方法来实现想要的效果,因此只能通过自定义view来实现. 通过这篇文章记录一下,便于之后需要实现类似的效果时查找使用. 如何实现 通过创建LinearGradient来实现颜色渐变,并将之设置到画笔Paint的着色器Shader,绘制想要的路径即可实现该效果. 实现代码如下: class GradientLineChart :

  • Android自定义View实现天气预报折线图

    本文实例为大家分享了Android自定义View画天气预报折线图的具体代码,供大家参考,具体内容如下 效果图如下: 刚开始尝试用第三方画曲线的框架来画效果图,后来发现曲线间的阴影当有负数的度数的时候画不出来,而且不需要点击放大.点点可点的效果,用框架显得很臃肿,所以最后用自定义View来画的折线图.自定义画折线图的大致思路:这个图是有多个四边形组成的(4个点连接起来就是一个四边形),两边延伸:添加四个多余的点,将左右的边距设置成负数即可. 代码如下: public class WeatherCh

  • Android自定义View实现渐变色仪表盘

    前言:最近一直在学自定义View的相关知识,感觉这在Android中还是挺难的一块,当然这也是每个程序员必经之路,正好公司项目要求实现类似仪表盘的效果用于直观的显示公司数据,于是就简单的写了个demo,记录实现的过程.上篇<Android自定义View实现圆弧进度效果>简单记录了圆弧及文字的绘制,渐变色的仪表盘效果将更加升入的介绍canvas及paint的使用(如画布旋转,paint的渐变色设置等). 知识梳理 1.圆弧渐变色(SweepGradient) 2.圆弧上刻度绘制 3.指针指示当前

  • Android自定义View实现圆形切图效果

    使用自定义View实现圆形ImageView的效果,具体内容如下 目前圆形边框还需要调整,这里有点问题 实现思路 使用一个Paint,将得到的Bitmap设置成paint的Shader,设置完成后,使用Matrix调整图片至居中,使用RectF约束边框,最后完成绘制 初始化Paint,设置Shader private void init() { getBitmapFromDrawable(); if (mBitmap == null) { return; } mShader = new Bitm

  • Android自定义View实现折线图效果

    下面就是结果图(每种状态用一个表情图片表示): 一.主页面的布局文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height=&quo

  • Android自定义View实现公交成轨迹图

    本文实例为大家分享了Android自定义View实现公交成轨迹图的具体代码,供大家参考,具体内容如下 总体分析下:水平方向recyclewview,item包含定位点,站台位置和站台名称. 下面看实现: 1.继承framelayout,实现构造方法: public class BusStopPlateView extends FrameLayout { ... public BusStopPlateView(@NonNull Context context) { super(context);

  • Android使用自定义View实现饼状图的实例代码

    本文讲述了Android使用自定义View实现饼状图的实例代码.分享给大家供大家参考,具体如下: 1.效果图 2.代码实现 public class PieChartView extends View { private Paint mPaint; private List<PieData>pieDataList; // 饼状图初始绘制角度 private float mStartAngle = 0; public PieChartView(Context context) { this(co

  • Android 自定义View实现芝麻分曲线图效果

    1.简介 其实这个效果几天之前就写了,但是一直没有更新博客,本来想着把芝麻分雷达图也做好再发博客的,然后今天看到鸿洋的微信公众号有朋友发了芝麻分的雷达图,所以就算了,算是一个互补吧.平时文章也写的比较少,所以可能有点杂乱,有什么需要改进的地方欢迎给出建议,不胜感激. 效果图: 2.步骤: 初始化View的属性 初始化画笔 绘制代表最高分和最低分的两根虚线 绘制文字 绘制代表月份的属性 绘制芝麻分折线 绘制代表芝麻分的圆点 绘制选中分数的悬浮文字以及背景 处理点击事件 3.编码: 初始化View属

  • Android自定义View实现柱状波形图的绘制

    目录 前言 实现 基本属性 设计监听器 绘制图形 左右拖动 完整代码 前言 柱状波形图是一种常见的图形.一个个柱子按顺序排列,构成一个波形图. 柱子的高度由输入数据决定.如果输入的是音频的音量,则可得到一个声波图. 在一些音频软件中,我们也可以左右拖动声波,来改变音频的播放进度 本文举例的自定View,实现如下功能: 以柱状形式展示数据的大小 标明图形当前最中间的数据 可以横向拖动进度,进度就是让某个特定的数据居中展示 可以改变左右两边的柱子颜色 可以调整柱子的宽度 拖动完毕后监听当前进度 实现

随机推荐