You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中如何将Canvas内LineChart移至指定坐标并解决图片生成失败问题

问题描述

现有代码可将LineChart视图转为PNG保存到手机,但尝试调整Canvas上LineChart的垂直(顶部)位置时,无论怎么操作都无法生成图片文件,不过文本可以正常移动。

现有实现代码

val thelinechart = findViewById<View>(R.id.lineChart) as LineChart

thelinechart.setOnClickListener {
    thelinechart.viewTreeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            thelinechart.viewTreeObserver.removeOnGlobalLayoutListener(this)
            val b = Bitmap.createBitmap(
                thelinechart.measuredWidth,
                thelinechart.measuredHeight+57,
                Bitmap.Config.RGB_565
            )
            val c = Canvas(b)

            val backgroundColor = Color.argb(255, 200, 220, 255)
            c.drawColor(backgroundColor)

            val paint = Paint()
            paint.color = Color.BLACK
            paint.textSize = 19f
            paint.setTextAlign(Paint.Align.CENTER)
            val typeface = Typeface.DEFAULT_BOLD
            paint.typeface = typeface
            val current = Date()
            c.drawText("My Chart - $current",
                (c.width/2).toFloat(), 25f, paint)

            thelinechart.layout(thelinechart.left, thelinechart.top, thelinechart.right, thelinechart.bottom)
            thelinechart.draw(c)

            val filename = "thegraph.png"
            val sd: String = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).toString()
            val dest = File(sd, filename)
            try {
                val out = FileOutputStream(dest)
                b.compress(Bitmap.CompressFormat.PNG, 90, out)
                out.flush()
                out.close()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    })
}

编辑补充:LineChart布局代码

<com.github.mikephil.charting.charts.LineChart
    android:id="@+id/lineChart"
    android:layout_width="match_parent"
    android:layout_height="117dp"
    android:layout_marginTop="8dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/llayout" />

解决方案

问题根源在于你调用的thelinechart.layout(...)方法——这个方法是用来在View的父布局中定位视图的,完全不是控制它在Canvas上的绘制位置。直接调用这个方法会打乱View的原有布局状态,导致后续绘制失败,自然生成不了图片。

要调整LineChart在Canvas上的垂直位置,正确的做法是用Canvas的translate方法偏移绘制坐标,具体修改步骤:

  1. 删掉thelinechart.layout(thelinechart.left, thelinechart.top, thelinechart.right, thelinechart.bottom)这一行代码。
  2. 在调用thelinechart.draw(c)之前,用translate设置垂直偏移量。比如想把图表往下移60dp(避开顶部的标题文本),先把dp转成像素:
    val offsetY = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60f, resources.displayMetrics)
    
  3. 用Canvas的save()和restore()包裹偏移绘制逻辑,避免影响后续操作:

修改后的核心代码片段:

// 绘制完标题文本后执行
val offsetY = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60f, resources.displayMetrics)
c.save() // 保存Canvas原始状态
c.translate(0f, offsetY) // 垂直偏移60dp
thelinechart.draw(c)
c.restore() // 恢复Canvas状态

另外,要保证Bitmap的高度足够容纳偏移后的图表和顶部文本。你当前设置的thelinechart.measuredHeight+57如果不够,可以根据偏移量调整,比如改成thelinechart.measuredHeight + (offsetY.toInt() + 20),防止图表被截断。

最后注意权限问题:Android 10及以上版本,原代码的文件写入方式可能失败,需要适配权限:

  • 在AndroidManifest.xml中添加权限:
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    
  • 动态申请权限,或者改用MediaStore方式保存文件。

这样修改后,就能正常生成带垂直偏移LineChart的图片了。


内容的提问来源于stack exchange,提问作者ThN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 00:14:53