我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android怎么实现自定义折线图控件

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android怎么实现自定义折线图控件

这篇“Android怎么实现自定义折线图控件”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android怎么实现自定义折线图控件”文章吧。

    前言

    日前,有一个“折现图”的需求,如下图所示:

    Android怎么实现自定义折线图控件

    概述

    如何自定义折线图?首先将折线图的绘制部分拆分成三部分:

    • 原点

    • X轴

    • Y轴

    • 折线

    原点

    第一步,需要定义出“折线图”原点的位置,由图得:

    Android怎么实现自定义折线图控件

    可以发现,原点的位置由X轴、Y轴所占空间决定:

    OriginX:Y轴宽度OriginY:View高度 - X轴高度

    计算Y轴宽度

    思路:遍历Y轴的绘制文字,用画笔测量其最大宽度,在加上其左右Margin间距即Y轴宽度

    Y轴宽度 = Y轴MarginLeft + Y轴最大文字宽度 + Y轴MariginRight

    计算X轴高度

    思路:获取X轴画笔FontMetrics,根据其top、bottom计算出X轴文字高度,在加上其上下Margin间距即X轴高度

    val fontMetrics = xAxisTextPaint.fontMetricsval lineHeight = fontMetrics.bottom - fontMetrics.topxAxisHeight = lineHeight + xAxisOptions.textMarginTop + xAxisOptions.textMarginBottom

    X轴

    第二步,根据原点位置,绘制X轴轴线、网格线、文本

    绘制轴线

    绘制轴线比较简单,沿原点向控件右侧画一条直线即可

    if (xAxisOptions.isEnableLine) {    xAxisLinePaint.strokeWidth = xAxisOptions.lineWidth    xAxisLinePaint.color = xAxisOptions.lineColor    xAxisLinePaint.pathEffect = xAxisOptions.linePathEffect    canvas.drawLine(originX, originY, width.toFloat(), originY, xAxisLinePaint)}

    X轴刻度间隔

    在绘制网格线、文本之前需要先计算X轴的刻度间隔:

    Android怎么实现自定义折线图控件

    这里处理的方式比较随意,直接将X轴等分7份即可(因为需要显示近7天的数据)

    xGap = (width - originX) / 7

    网格线、文本

    网格线:只需要根据X轴的刻度,沿Y轴方向依次向控件顶部,画直线即可

    文本:文本需要通过画笔,提前测量出待绘制文本的区域,然后计算出居中位置绘制即可

    xAxisTexts.forEachIndexed { index, text ->    val pointX = originX + index * xGap    //刻度线    if (xAxisOptions.isEnableRuler) {        xAxisLinePaint.strokeWidth = xAxisOptions.rulerWidth        xAxisLinePaint.color = xAxisOptions.rulerColor        canvas.drawLine(            pointX, originY,            pointX, originY - xAxisOptions.rulerHeight,            xAxisLinePaint        )    }    //网格线    if (xAxisOptions.isEnableGrid) {        xAxisLinePaint.strokeWidth = xAxisOptions.gridWidth        xAxisLinePaint.color = xAxisOptions.gridColor        xAxisLinePaint.pathEffect = xAxisOptions.gridPathEffect        canvas.drawLine(pointX, originY, pointX, 0f, xAxisLinePaint)    }    //文本    bounds.setEmpty()    xAxisTextPaint.textSize = xAxisOptions.textSize    xAxisTextPaint.color = xAxisOptions.textColor    xAxisTextPaint.getTextBounds(text, 0, text.length, bounds)    val fm = xAxisTextPaint.fontMetrics    val fontHeight = fm.bottom - fm.top    val fontX = originX + index * xGap + (xGap - bounds.width()) / 2f    val fontBaseline = originY + (xAxisHeight - fontHeight) / 2f - fm.top    canvas.drawText(text, fontX, fontBaseline, xAxisTextPaint)}

    Y轴

    第三步:根据原点位置,绘制Y轴轴线、网格线、文本

    计算Y轴分布

    个人认为,这里是自定义折线图的一个难点,这里经过查阅资料,使用该文章中的算法:

    基于JavaScript实现数值型坐标轴刻度计算算法(echarts的y轴刻度计算)

    private fun getYInterval(maxY: Int): Int {    val yIntervalCount = yAxisCount - 1    val rawInterval = maxY / yIntervalCount.toFloat()    val magicPower = floor(log10(rawInterval.toDouble()))    var magic = 10.0.pow(magicPower).toFloat()    if (magic == rawInterval) {        magic = rawInterval    } else {        magic *= 10    }    val rawStandardInterval = rawInterval / magic    val standardInterval = getStandardInterval(rawStandardInterval) * magic    return standardInterval.roundToInt()}private fun getStandardInterval(x: Float): Float {    return when {        x <= 0.1f -> 0.1f        x <= 0.2f -> 0.2f        x <= 0.25f -> 0.25f        x <= 0.5f -> 0.5f        x <= 1f -> 1f        else -> getStandardInterval(x / 10) * 10    }}

    刻度间隔、网格线、文本

    Y轴的轴线、网格线、文本剩下的内容与X轴的处理方式几乎一致

    //绘制Y轴//轴线if (yAxisOptions.isEnableLine) {    yAxisLinePaint.strokeWidth = yAxisOptions.lineWidth    yAxisLinePaint.color = yAxisOptions.lineColor    yAxisLinePaint.pathEffect = yAxisOptions.linePathEffect    canvas.drawLine(originX, 0f, originX, originY, yAxisLinePaint)}yAxisTexts.forEachIndexed { index, text ->    //刻度线    val pointY = originY - index * yGap    if (yAxisOptions.isEnableRuler) {        yAxisLinePaint.strokeWidth = yAxisOptions.rulerWidth        yAxisLinePaint.color = yAxisOptions.rulerColor        canvas.drawLine(            originX,            pointY,            originX + yAxisOptions.rulerHeight,            pointY,            yAxisLinePaint        )    }    //网格线    if (yAxisOptions.isEnableGrid) {        yAxisLinePaint.strokeWidth = yAxisOptions.gridWidth        yAxisLinePaint.color = yAxisOptions.gridColor        yAxisLinePaint.pathEffect = yAxisOptions.gridPathEffect        canvas.drawLine(originX, pointY, width.toFloat(), pointY, yAxisLinePaint)    }    //文本    bounds.setEmpty()    yAxisTextPaint.textSize = yAxisOptions.textSize    yAxisTextPaint.color = yAxisOptions.textColor    yAxisTextPaint.getTextBounds(text, 0, text.length, bounds)    val fm = yAxisTextPaint.fontMetrics    val x = (yAxisWidth - bounds.width()) / 2f    val fontHeight = fm.bottom - fm.top    val y = originY - index * yGap - fontHeight / 2f - fm.top    canvas.drawText(text, x, y, yAxisTextPaint)}

    折线

    折线的连接,这里使用的是Path,将一个一个坐标点连接,最后将Path绘制,就形成了图中的折线图

    //绘制数据path.reset()points.forEachIndexed { index, point ->    val x = originX + index * xGap + xGap / 2f    val y = originY - (point.yAxis.toFloat() / yAxisMaxValue) * (yGap * (yAxisCount - 1))    if (index == 0) {        path.moveTo(x, y)    } else {        path.lineTo(x, y)    }    //圆点    circlePaint.color = dataOptions.circleColor    canvas.drawCircle(x, y, dataOptions.circleRadius, circlePaint)}pathPaint.strokeWidth = dataOptions.pathWidthpathPaint.color = dataOptions.pathColorcanvas.drawPath(path, pathPaint)

    值得注意的是:坐标点X根据间隔是相对确定的,而坐标点Y则需要进行百分比换算

    代码

    折线图LineChart

    package com.vander.pool.widget.linechartimport android.content.Contextimport android.graphics.*import android.text.TextPaintimport android.util.AttributeSetimport android.view.Viewimport java.text.DecimalFormatimport kotlin.math.floorimport kotlin.math.log10import kotlin.math.powimport kotlin.math.roundToIntclass LineChart : View {    private var options = ChartOptions()        private val xAxisTextPaint = TextPaint(Paint.ANTI_ALIAS_FLAG)    private val xAxisLinePaint = Paint(Paint.ANTI_ALIAS_FLAG)    private val xAxisTexts = mutableListOf<String>()    private var xAxisHeight = 0f        private val yAxisTextPaint = TextPaint(Paint.ANTI_ALIAS_FLAG)    private val yAxisLinePaint = Paint(Paint.ANTI_ALIAS_FLAG)    private val yAxisTexts = mutableListOf<String>()    private var yAxisWidth = 0f    private val yAxisCount = 5    private var yAxisMaxValue: Int = 0        private var originX = 0f    private var originY = 0f    private var xGap = 0f    private var yGap = 0f        private val pathPaint = Paint(Paint.ANTI_ALIAS_FLAG).also {        it.style = Paint.Style.STROKE    }    private val circlePaint = Paint(Paint.ANTI_ALIAS_FLAG).also {        it.color = Color.parseColor("#79EBCF")        it.style = Paint.Style.FILL    }    private val points = mutableListOf<ChartBean>()    private val bounds = Rect()    private val path = Path()    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)    override fun onDraw(canvas: Canvas) {        super.onDraw(canvas)        if (points.isEmpty()) return        val xAxisOptions = options.xAxisOptions        val yAxisOptions = options.yAxisOptions        val dataOptions = options.dataOptions        //设置原点        originX = yAxisWidth        originY = height - xAxisHeight        //设置X轴Y轴间隔        xGap = (width - originX) / points.size        //Y轴默认顶部会留出一半空间        yGap = originY / (yAxisCount - 1 + 0.5f)        //绘制X轴        //轴线        if (xAxisOptions.isEnableLine) {            xAxisLinePaint.strokeWidth = xAxisOptions.lineWidth            xAxisLinePaint.color = xAxisOptions.lineColor            xAxisLinePaint.pathEffect = xAxisOptions.linePathEffect            canvas.drawLine(originX, originY, width.toFloat(), originY, xAxisLinePaint)        }        xAxisTexts.forEachIndexed { index, text ->            val pointX = originX + index * xGap            //刻度线            if (xAxisOptions.isEnableRuler) {                xAxisLinePaint.strokeWidth = xAxisOptions.rulerWidth                xAxisLinePaint.color = xAxisOptions.rulerColor                canvas.drawLine(                    pointX, originY,                    pointX, originY - xAxisOptions.rulerHeight,                    xAxisLinePaint                )            }            //网格线            if (xAxisOptions.isEnableGrid) {                xAxisLinePaint.strokeWidth = xAxisOptions.gridWidth                xAxisLinePaint.color = xAxisOptions.gridColor                xAxisLinePaint.pathEffect = xAxisOptions.gridPathEffect                canvas.drawLine(pointX, originY, pointX, 0f, xAxisLinePaint)            }            //文本            bounds.setEmpty()            xAxisTextPaint.textSize = xAxisOptions.textSize            xAxisTextPaint.color = xAxisOptions.textColor            xAxisTextPaint.getTextBounds(text, 0, text.length, bounds)            val fm = xAxisTextPaint.fontMetrics            val fontHeight = fm.bottom - fm.top            val fontX = originX + index * xGap + (xGap - bounds.width()) / 2f            val fontBaseline = originY + (xAxisHeight - fontHeight) / 2f - fm.top            canvas.drawText(text, fontX, fontBaseline, xAxisTextPaint)        }        //绘制Y轴        //轴线        if (yAxisOptions.isEnableLine) {            yAxisLinePaint.strokeWidth = yAxisOptions.lineWidth            yAxisLinePaint.color = yAxisOptions.lineColor            yAxisLinePaint.pathEffect = yAxisOptions.linePathEffect            canvas.drawLine(originX, 0f, originX, originY, yAxisLinePaint)        }        yAxisTexts.forEachIndexed { index, text ->            //刻度线            val pointY = originY - index * yGap            if (yAxisOptions.isEnableRuler) {                yAxisLinePaint.strokeWidth = yAxisOptions.rulerWidth                yAxisLinePaint.color = yAxisOptions.rulerColor                canvas.drawLine(                    originX,                    pointY,                    originX + yAxisOptions.rulerHeight,                    pointY,                    yAxisLinePaint                )            }            //网格线            if (yAxisOptions.isEnableGrid) {                yAxisLinePaint.strokeWidth = yAxisOptions.gridWidth                yAxisLinePaint.color = yAxisOptions.gridColor                yAxisLinePaint.pathEffect = yAxisOptions.gridPathEffect                canvas.drawLine(originX, pointY, width.toFloat(), pointY, yAxisLinePaint)            }            //文本            bounds.setEmpty()            yAxisTextPaint.textSize = yAxisOptions.textSize            yAxisTextPaint.color = yAxisOptions.textColor            yAxisTextPaint.getTextBounds(text, 0, text.length, bounds)            val fm = yAxisTextPaint.fontMetrics            val x = (yAxisWidth - bounds.width()) / 2f            val fontHeight = fm.bottom - fm.top            val y = originY - index * yGap - fontHeight / 2f - fm.top            canvas.drawText(text, x, y, yAxisTextPaint)        }        //绘制数据        path.reset()        points.forEachIndexed { index, point ->            val x = originX + index * xGap + xGap / 2f            val y = originY - (point.yAxis.toFloat() / yAxisMaxValue) * (yGap * (yAxisCount - 1))            if (index == 0) {                path.moveTo(x, y)            } else {                path.lineTo(x, y)            }            //圆点            circlePaint.color = dataOptions.circleColor            canvas.drawCircle(x, y, dataOptions.circleRadius, circlePaint)        }        pathPaint.strokeWidth = dataOptions.pathWidth        pathPaint.color = dataOptions.pathColor        canvas.drawPath(path, pathPaint)    }        fun setData(list: List<ChartBean>) {        points.clear()        points.addAll(list)        //设置X轴、Y轴数据        setXAxisData(list)        setYAxisData(list)        invalidate()    }        private fun setXAxisData(list: List<ChartBean>) {        val xAxisOptions = options.xAxisOptions        val values = list.map { it.xAxis }        //X轴文本        xAxisTexts.clear()        xAxisTexts.addAll(values)        //X轴高度        val fontMetrics = xAxisTextPaint.fontMetrics        val lineHeight = fontMetrics.bottom - fontMetrics.top        xAxisHeight = lineHeight + xAxisOptions.textMarginTop + xAxisOptions.textMarginBottom    }        private fun setYAxisData(list: List<ChartBean>) {        val yAxisOptions = options.yAxisOptions        yAxisTextPaint.textSize = yAxisOptions.textSize        yAxisTextPaint.color = yAxisOptions.textColor        val texts = list.map { it.yAxis.toString() }        yAxisTexts.clear()        yAxisTexts.addAll(texts)        //Y轴高度        val maxTextWidth = yAxisTexts.maxOf { yAxisTextPaint.measureText(it) }        yAxisWidth = maxTextWidth + yAxisOptions.textMarginLeft + yAxisOptions.textMarginRight        //Y轴间隔        val maxY = list.maxOf { it.yAxis }        val interval = when {            maxY <= 10 -> getYInterval(10)            else -> getYInterval(maxY)        }        //Y轴文字        yAxisTexts.clear()        for (index in 0..yAxisCount) {            val value = index * interval            yAxisTexts.add(formatNum(value))        }        yAxisMaxValue = (yAxisCount - 1) * interval    }        private fun formatNum(num: Int): String {        val absNum = Math.abs(num)        return if (absNum >= 0 && absNum < 1000) {            return num.toString()        } else {            val format = DecimalFormat("0.0")            val value = num / 1000f            "${format.format(value)}k"        }    }        private fun getYInterval(maxY: Int): Int {        val yIntervalCount = yAxisCount - 1        val rawInterval = maxY / yIntervalCount.toFloat()        val magicPower = floor(log10(rawInterval.toDouble()))        var magic = 10.0.pow(magicPower).toFloat()        if (magic == rawInterval) {            magic = rawInterval        } else {            magic *= 10        }        val rawStandardInterval = rawInterval / magic        val standardInterval = getStandardInterval(rawStandardInterval) * magic        return standardInterval.roundToInt()    }        private fun getStandardInterval(x: Float): Float {        return when {            x <= 0.1f -> 0.1f            x <= 0.2f -> 0.2f            x <= 0.25f -> 0.25f            x <= 0.5f -> 0.5f            x <= 1f -> 1f            else -> getStandardInterval(x / 10) * 10        }    }        fun setOptions(newOptions: ChartOptions) {        this.options = newOptions        setData(points)    }    fun getOptions(): ChartOptions {        return options    }    data class ChartBean(val xAxis: String, val yAxis: Int)}

    ChartOptions配置选项:

    class ChartOptions {    //X轴配置    var xAxisOptions = AxisOptions()    //Y轴配置    var yAxisOptions = AxisOptions()    //数据配置    var dataOptions = DataOptions()}class AxisOptions {   companion object {     private const val DEFAULT_TEXT_SIZE = 20f       private const val DEFAULT_TEXT_COLOR = Color.BLACK        private const val DEFAULT_TEXT_MARGIN = 20        private const val DEFAULT_LINE_WIDTH = 2f        private const val DEFAULT_RULER_WIDTH = 10f    }        @FloatRange(from = 1.0)    var textSize: Float = DEFAULT_TEXT_SIZE    @ColorInt    var textColor: Int = DEFAULT_TEXT_COLOR        var textMarginTop: Int = DEFAULT_TEXT_MARGIN    var textMarginBottom: Int = DEFAULT_TEXT_MARGIN        var textMarginLeft: Int = DEFAULT_TEXT_MARGIN    var textMarginRight: Int = DEFAULT_TEXT_MARGIN        var lineWidth: Float = DEFAULT_LINE_WIDTH    @ColorInt    var lineColor: Int = DEFAULT_TEXT_COLOR    var isEnableLine = true   var linePathEffect: PathEffect? = null        var rulerWidth = DEFAULT_LINE_WIDTH    var rulerHeight = DEFAULT_RULER_WIDTH    @ColorInt    var rulerColor = DEFAULT_TEXT_COLOR    var isEnableRuler = true        var gridWidth: Float = DEFAULT_LINE_WIDTH    @ColorInt    var gridColor: Int = DEFAULT_TEXT_COLOR    var gridPathEffect: PathEffect? = null    var isEnableGrid = true}class DataOptions {    companion object {        private const val DEFAULT_PATH_WIDTH = 2f        private const val DEFAULT_PATH_COLOR = Color.BLACK        private const val DEFAULT_CIRCLE_RADIUS = 10f        private const val DEFAULT_CIRCLE_COLOR = Color.BLACK    }    var pathWidth = DEFAULT_PATH_WIDTH    var pathColor = DEFAULT_PATH_COLOR    var circleRadius = DEFAULT_CIRCLE_RADIUS    var circleColor = DEFAULT_CIRCLE_COLOR}

    Demo样式:

    private fun initView() {    val options = binding.chart.getOptions()    //X轴    val xAxisOptions = options.xAxisOptions    xAxisOptions.isEnableLine = false    xAxisOptions.textColor = Color.parseColor("#999999")    xAxisOptions.textSize = dpToPx(12)    xAxisOptions.textMarginTop = dpToPx(12).toInt()    xAxisOptions.textMarginBottom = dpToPx(12).toInt()    xAxisOptions.isEnableGrid = false    xAxisOptions.isEnableRuler = false    //Y轴    val yAxisOptions = options.yAxisOptions    yAxisOptions.isEnableLine = false    yAxisOptions.textColor = Color.parseColor("#999999")    yAxisOptions.textSize = dpToPx(12)    yAxisOptions.textMarginLeft = dpToPx(12).toInt()    yAxisOptions.textMarginRight = dpToPx(12).toInt()    yAxisOptions.gridColor = Color.parseColor("#999999")    yAxisOptions.gridWidth = dpToPx(0.5f)    val dashLength = dpToPx(8f)    yAxisOptions.gridPathEffect = DashPathEffect(floatArrayOf(dashLength, dashLength / 2), 0f)    yAxisOptions.isEnableRuler = false    //数据    val dataOptions = options.dataOptions    dataOptions.pathColor = Color.parseColor("#79EBCF")    dataOptions.pathWidth = dpToPx(1f)    dataOptions.circleColor = Color.parseColor("#79EBCF")    dataOptions.circleRadius = dpToPx(3f)    binding.chart.setOnClickListener {        initChartData()    }    binding.toolbar.setLeftClick {        finish()    }}private fun initChartData() {    val random = 1000    val list = mutableListOf<LineChart.ChartBean>()    list.add(LineChart.ChartBean("05-01", Random.nextInt(random)))    list.add(LineChart.ChartBean("05-02", Random.nextInt(random)))    list.add(LineChart.ChartBean("05-03", Random.nextInt(random)))    list.add(LineChart.ChartBean("05-04", Random.nextInt(random)))    list.add(LineChart.ChartBean("05-05", Random.nextInt(random)))    list.add(LineChart.ChartBean("05-06", Random.nextInt(random)))    list.add(LineChart.ChartBean("05-07", Random.nextInt(random)))    binding.chart.setData(list)    //文本    val text = list.joinToString("\n") {        "x : ${it.xAxis}  y:${it.yAxis}"    }    binding.value.text = text}

    以上就是关于“Android怎么实现自定义折线图控件”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网行业资讯频道。

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    Android怎么实现自定义折线图控件

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    Android怎么实现自定义折线图控件

    这篇“Android怎么实现自定义折线图控件”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android怎么实现自定义折线图
    2023-07-02

    Android自定义View简易折线图控件(二)

    继续练习自定义View,这次带来的是简易折线图,支持坐标点点击监听,效果如下:画坐标轴、画刻度、画点、连线。。x、y轴的数据范围是写死的 1 <= x <= 7 ,1 <= y <= 70 。。写活的话涉及到坐标轴刻度的动态计算、坐标点的坐
    2022-06-06

    Android自定义折线图控件的完整步骤

    目录前言概述原点计算Y轴宽度计算X轴高度X轴绘制轴线X轴刻度间隔网格线、文本Y轴计算Y轴分布刻度间隔、网格线、文本折线代码总结前言 日前,有一个“折现图”的需求,如下图所示:概述 如何自定义折线图?首先将折线图的绘制
    Android自定义折线图控件的完整步骤
    2022-06-07

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

    下面就是结果图(每种状态用一个表情图片表示):一、主页面的布局文件如下:
    2022-06-06

    Android怎么自定义View实现渐变色折线图

    这篇文章主要介绍“Android怎么自定义View实现渐变色折线图”,在日常操作中,相信很多人在Android怎么自定义View实现渐变色折线图问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Android怎么
    2023-06-30

    Android自定义控件实现简单的轮播图控件

    最近要做一个轮播图的效果,网上看了几篇文章,基本上都能找到实现,效果还挺不错,但是在写的时候感觉每次都要单独去重新在Activity里写一堆代码。于是自己封装了一下。本篇轮播图实现原理原文出处:循环广告位组件的实现,这里只是做了下封装成一个
    2022-06-06

    Android开发怎么自定义实时图表控件

    本文小编为大家详细介绍“Android开发怎么自定义实时图表控件”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android开发怎么自定义实时图表控件”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。演示环境开发工
    2023-07-02

    自定义视图view的折线图怎么使用

    这篇文章主要讲解了“自定义视图view的折线图怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“自定义视图view的折线图怎么使用”吧!绘制折线图预览图绘制这个折线图需要都需要哪些步骤?
    2023-07-05

    Android自定义控件(实现状态提示图表)

    前面分析那么多系统源码了,也该暂停下来休息一下,趁昨晚闲着看见一个有意思的需求就操练一下分析源码后的实例演练—-自定义控件。 这个实例很适合新手入门自定义控件。先看下效果图: 横屏模式如下: 竖屏模式如下: 看见没有,这个控件完全自定义的
    2022-06-06

    Android自定义View实现多图片选择控件

    前言 相信很多朋友在开发中都会遇到图片上传的情况,尤其是多图上传,最经典的莫过于微信的图片选择了。所有很多情况下会使用到多图选择,所以就有了这篇文章,今天抽点时间写了个控件。 支持自定义选择图片的样式 支持设置图片选择数量 支持图片预
    2022-06-06

    Android实现自定义轮播图片控件示例

    要完成一个轮播图片,首先想到的应该是使用ViewPager来实现。ViewPager已经有了滑动的功能,我们只要让它自己滚动。再加上下方的小圆点就行了。所以我们本次的自定义控件就是由ViewPager和LinearLayout叠加起来组成的
    2022-06-06

    Android实现自定义轮播图片控件详解

    首先上效果图实现原理 要完成一个轮播图片,首先想到的应该是使用ViewPager来实现。ViewPager已经有了滑动的功能,我们只要让它自己滚动。再加上下方的小圆点就行了。所以我们本次的自定义控件就是由ViewPager和LinearLa
    2022-06-06

    怎么在Android中实现一个自定义控件

    今天就跟大家聊聊有关怎么在Android中实现一个自定义控件,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。首先定义一个layout实现按钮内部布局:
    2023-05-31

    编程热搜

    • Python 学习之路 - Python
      一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
      Python 学习之路 - Python
    • chatgpt的中文全称是什么
      chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
      chatgpt的中文全称是什么
    • C/C++中extern函数使用详解
    • C/C++可变参数的使用
      可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
      C/C++可变参数的使用
    • css样式文件该放在哪里
    • php中数组下标必须是连续的吗
    • Python 3 教程
      Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
      Python 3 教程
    • Python pip包管理
      一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
      Python pip包管理
    • ubuntu如何重新编译内核
    • 改善Java代码之慎用java动态编译

    目录