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

如何提高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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 14:30:04