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

如何获取Android锁屏可见屏幕宽度?锁屏位图居中失败求助

锁屏位图居中失败的问题排查与解决

问题描述

  • 在Android锁屏上尝试居中显示位图时,发现部分屏幕区域不可见,无法找到锁屏边距的相关细节
  • 测试代码绘制了居中的10x10红色方块和刻度标尺,结果显示可见范围仅在30到620之间,导致居中计算完全失效
  • 系统自带的锁屏图标可以正确居中,但自定义绘制的红色方块位置明显错误

测试代码

fun DrawRuler(context: Context)
{
    val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    paint.color = Color.WHITE

    var densityDpi = Resources.getSystem().displayMetrics.densityDpi
    var density = Resources.getSystem().displayMetrics.density
    var xdpi = Resources.getSystem().displayMetrics.xdpi
    var ydpi = Resources.getSystem().displayMetrics.ydpi

    var screenWidth_int = Resources.getSystem().displayMetrics.widthPixels
    var screenHeight_int = Resources.getSystem().displayMetrics.heightPixels
    var screenWidth = screenWidth_int.toFloat()

    var wallpaper = Bitmap.createBitmap(screenWidth_int   , screenHeight_int, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(wallpaper)

    val textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    textPaint.color = Color.WHITE
    textPaint.setTextSize(40f);

    canvas.drawText("densityDpi       = $densityDpi"       , 40f,   850f, textPaint)
    canvas.drawText("density          = $density"          , 40f,   900f, textPaint)
    canvas.drawText("xdpi             = $xdpi"             , 40f,   950f, textPaint)
    canvas.drawText("ydpi             = $ydpi"             , 40f,  1000f, textPaint)
    canvas.drawText("screenWidth_int  = $screenWidth_int"  , 40f,  1050f, textPaint)
    canvas.drawText("screenHeight_int = $screenHeight_int" , 40f,  1100f, textPaint)

    // Draw a red 10x10 block and attempt to centre it.
    val bitmap1 = Bitmap.createBitmap(10,10, Bitmap.Config.ARGB_8888)
    val image1 = Canvas(bitmap1)
    image1.drawColor(Color.RED);
    var redLeft = ((screenWidth-10F)/2F)
    canvas.drawBitmap(bitmap1 , redLeft, 1200f, Paint(Paint.ANTI_ALIAS_FLAG))
    canvas.drawText("left = $redLeft" , redLeft,  1150f, textPaint)

    // Draw ruler
    var rulerPos = 1158f;

    canvas.drawLine(0f, rulerPos, screenWidth, rulerPos, paint)

    var x = 0f;
    while (x <= screenWidth )
    {
        var thisDepth = 5f;
        if (x % 10 == 0F) thisDepth = 10f
        if (x % 50 == 0F) {
            thisDepth = 20f
            canvas.drawText(x.toString(), x, rulerPos + 30F, paint)
        }

        canvas.drawLine(x, rulerPos, x, rulerPos + thisDepth, paint)
        x = x + 5f
    }

    val wallpaperManager = WallpaperManager.getInstance(context)
    wallpaperManager.setBitmap(wallpaper,  null, false, WallpaperManager.FLAG_LOCK)
    wallpaper.recycle()

}

问题根源

  1. 错误使用物理屏幕尺寸:你通过Resources.getSystem().displayMetrics获取的是设备物理屏幕的完整尺寸,但锁屏壁纸的实际显示区域会被系统裁剪或偏移——系统会自动适配刘海屏、状态栏/导航栏、锁屏安全区域等UI元素,导致物理尺寸和实际可用显示区域不匹配。
  2. 未遵循锁屏壁纸适配规则:系统锁屏图标能正确居中,是因为它绘制在系统预设的锁屏安全区域内;而你直接按物理屏幕尺寸计算居中位置,完全忽略了系统对锁屏壁纸的缩放、偏移规则。
  3. 壁纸设置参数错误:调用setBitmap()时传入null作为偏移量参数,系统会自动应用默认的偏移策略,进一步导致你绘制的居中位置和实际显示位置脱节。

修复方案

修改后的代码

fun DrawRuler(context: Context) {
    val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    paint.color = Color.WHITE

    val wallpaperManager = WallpaperManager.getInstance(context)
    // 获取系统推荐的锁屏壁纸有效尺寸(已适配UI元素)
    val lockScreenWidth = wallpaperManager.desiredMinimumWidth
    val lockScreenHeight = wallpaperManager.desiredMinimumHeight

    val textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    textPaint.color = Color.WHITE
    textPaint.setTextSize(40f)

    // 基于锁屏有效尺寸创建Bitmap
    val wallpaper = Bitmap.createBitmap(lockScreenWidth, lockScreenHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(wallpaper)

    // 绘制调试信息
    canvas.drawText("lockScreenWidth = $lockScreenWidth", 40f, 850f, textPaint)
    canvas.drawText("lockScreenHeight = $lockScreenHeight", 40f, 900f, textPaint)

    // 基于锁屏有效尺寸计算居中位置
    val bitmap1 = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
    val image1 = Canvas(bitmap1)
    image1.drawColor(Color.RED)
    val redLeft = ((lockScreenWidth - 10F) / 2F)
    canvas.drawBitmap(bitmap1, redLeft, 1200f, Paint(Paint.ANTI_ALIAS_FLAG))
    canvas.drawText("left = $redLeft", redLeft, 1150f, textPaint)

    // 绘制适配锁屏尺寸的标尺
    val rulerPos = 1158f
    canvas.drawLine(0f, rulerPos, lockScreenWidth.toFloat(), rulerPos, paint)

    var x = 0f
    while (x <= lockScreenWidth) {
        var thisDepth = 5f
        if (x % 10 == 0F) thisDepth = 10f
        if (x % 50 == 0F) {
            thisDepth = 20f
            canvas.drawText(x.toString(), x, rulerPos + 30F, paint)
        }
        canvas.drawLine(x, rulerPos, x, rulerPos + thisDepth, paint)
        x += 5f
    }

    // 设置锁屏壁纸,禁用系统缩放,确保绘制内容准确显示
    wallpaperManager.setBitmap(wallpaper, null, true, WallpaperManager.FLAG_LOCK)
    wallpaper.recycle()
}

关键修改点说明

  • 使用WallpaperManager.desiredMinimumWidth/Height获取系统适配后的锁屏有效尺寸,这个尺寸已经考虑了所有UI元素对显示区域的影响
  • 基于锁屏有效尺寸计算居中位置,确保绘制内容落在实际可见区域内
  • 调用setBitmap()时将第三个参数设为true,禁用系统自动缩放,保证你的绘制内容按原尺寸显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:07:25