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方法偏移绘制坐标,具体修改步骤:
- 删掉
thelinechart.layout(thelinechart.left, thelinechart.top, thelinechart.right, thelinechart.bottom)这一行代码。 - 在调用
thelinechart.draw(c)之前,用translate设置垂直偏移量。比如想把图表往下移60dp(避开顶部的标题文本),先把dp转成像素:val offsetY = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60f, resources.displayMetrics) - 用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
相关产品推荐
相关产品推荐

