如何提高Android Canvas中文字阴影的不透明度与强度
问题根因
- 你创建Bitmap时使用了
Bitmap.Config.RGB_565配置,该格式没有Alpha通道,无法正常渲染带透明度的阴影模糊效果,直接导致阴影发暗、形状异常 setShadowLayer依赖软件渲染才能生效,你注释了开启软件层的代码,且即使开启也应该在绘制前设置,而非绘制到Bitmap后再给ImageView设置- 阴影半径、偏移参数和你想要的外发光效果不匹配
修复后的Canvas实现代码
class MainActivity : AppCompatActivity() { private lateinit var canvasIV: ImageView private lateinit var imgBitmap: Bitmap private lateinit var canvas: Canvas override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) canvasIV = findViewById(R.id.canvasIV) val displayMetrics = DisplayMetrics() windowManager.defaultDisplay.getMetrics(displayMetrics) val height = displayMetrics.heightPixels val width = displayMetrics.widthPixels // 改用带Alpha通道的Bitmap配置,才能正常渲染模糊阴影 imgBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) canvas = Canvas(imgBitmap) // 按需绘制背景色,这里用白色适配示例效果 canvas.drawColor(Color.WHITE) val tSize = 80.0f val shadowPaint = Paint() shadowPaint.isAntiAlias = true shadowPaint.color = Color.parseColor("#F897B9") shadowPaint.textSize = tSize shadowPaint.style = Paint.Style.FILL // 设置外发光效果的阴影参数:半径30,无偏移,阴影颜色和文字颜色一致 shadowPaint.setShadowLayer(30f, 0f, 0f, Color.parseColor("#F897B9")) // 关闭硬件加速避免阴影失效 canvasIV.setLayerType(View.LAYER_TYPE_SOFTWARE, null) canvas.drawText("Sayok Dey Majumder", 50f, 200f, shadowPaint) canvasIV.setImageDrawable(BitmapDrawable(resources, imgBitmap)) // 如需直接保存图片到磁盘,调用下面的方法即可 saveBitmapToDisk(imgBitmap) } // 保存Bitmap到本地存储 private fun saveBitmapToDisk(bitmap: Bitmap) { val saveFile = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "text_shadow.png") FileOutputStream(saveFile).use { fos -> bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos) } // 可选:通知系统相册更新 MediaScannerConnection.scanFile(this, arrayOf(saveFile.absolutePath), arrayOf("image/png"), null) } fun convertToPixels(context: Context, nDP: Int): Float { val conversionScale: Float = context.resources.displayMetrics.density return (nDP * conversionScale + 0.5f) } fun getTextWidth(text: String, paint: Paint): Int { val bounds = Rect() paint.getTextBounds(text, 0, text.length, bounds) return bounds.left + bounds.width() } fun getTextHeight(text: String, paint: Paint): Int { val bounds = Rect() paint.getTextBounds(text, 0, text.length, bounds) return bounds.bottom + bounds.height() } }
注:如果要保存图片到公共存储目录,需要动态申请存储权限:Android 12及以下申请WRITE_EXTERNAL_STORAGE,Android 13及以上申请READ_MEDIA_IMAGES
替代方案(不使用Canvas直接生成图片)
可以借助原生TextView配置样式后导出绘制内容为Bitmap,实现更简单:
private fun generateTextBitmap(): Bitmap { val textView = TextView(this) textView.text = "Sayok Dey Majumder" textView.textSize = 80f textView.setTextColor(Color.parseColor("#F897B9")) textView.setShadowLayer(30f, 0f, 0f, Color.parseColor("#F897B9")) textView.setBackgroundColor(Color.WHITE) // 测量TextView尺寸 textView.measure( View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) ) textView.layout(0, 0, textView.measuredWidth, textView.measuredHeight) // 生成Bitmap val bitmap = Bitmap.createBitmap(textView.measuredWidth, textView.measuredHeight, Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) textView.draw(canvas) return bitmap }
调用该方法拿到Bitmap后,复用上面的saveBitmapToDisk方法就能直接保存到磁盘。
内容的提问来源于stack exchange,提问作者Sayok Majumder
相关产品推荐
相关产品推荐

