You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Android Studio中实现示例图中的右上角悬浮层?

实现Android右上角悬浮Overlay的完整方案

嘿,我刚好折腾过类似的悬浮层功能,给你梳理下核心步骤,照着来就能搞定图里那个右上角的悬浮Overlay啦!

一、先搞定悬浮窗权限

这是第一步也是最关键的,Android对悬浮窗权限管得很严:

  • AndroidManifest.xml里先声明权限:
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    
  • Android 6.0+需要动态判断权限,如果没有的话,引导用户去设置开启:
    if (!Settings.canDrawOverlays(context)) {
        val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.packageName))
        startActivityForResult(intent, REQUEST_OVERLAY_PERMISSION)
    }
    
    注意:部分定制ROM(比如小米、华为)的权限逻辑有点特殊,可能需要额外引导用户去对应品牌的权限管理页开启。

二、创建悬浮层布局

你可以用XML写个自定义布局,也可以直接用代码创建View。比如做个简单的悬浮提示框:

<!-- res/layout/floating_overlay.xml -->
<TextView
    android:id="@+id/floating_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#CC000000"
    android:textColor="#FFFFFF"
    android:text="悬浮提示"
    android:padding="8dp"
    android:radius="4dp"/>

三、配置WindowManager参数

悬浮层是通过WindowManager来管理的,核心是设置LayoutParams,尤其是要让它显示在右上角:

val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val inflater = LayoutInflater.from(context)
val floatingView = inflater.inflate(R.layout.floating_overlay, null)

// 配置LayoutParams
val params = WindowManager.LayoutParams().apply {
    // Android 8.0+用这个类型,低版本可以用TYPE_SYSTEM_ALERT(不过已废弃)
    type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
    } else {
        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
    }
    // 设置右上角显示
    gravity = Gravity.TOP or Gravity.RIGHT
    // 偏移量,右边和上边各留20dp
    x = dpToPx(context, 20)
    y = dpToPx(context, 20)
    // 宽高自适应
    width = WindowManager.LayoutParams.WRAP_CONTENT
    height = WindowManager.LayoutParams.WRAP_CONTENT
    // 窗口不获取焦点,不影响下面页面的操作
    flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    // 背景透明
    format = PixelFormat.TRANSLUCENT
}

这里的dpToPx是个工具方法,把dp转成像素,方便适配不同屏幕:

fun dpToPx(context: Context, dp: Int): Int {
    return (dp * context.resources.displayMetrics.density).toInt()
}

四、添加悬浮层到屏幕

拿到WindowManagerparams后,直接把View加进去就行:

windowManager.addView(floatingView, params)

记得在不需要的时候(比如页面销毁、Service停止)移除它,避免内存泄漏:

if (floatingView.isAttachedToWindow) {
    windowManager.removeView(floatingView)
}

五、可选:给悬浮层加交互

如果想让用户能拖动悬浮层,只需要给View加个触摸监听:

floatingView.setOnTouchListener(object : View.OnTouchListener {
    private var lastX = 0
    private var lastY = 0
    override fun onTouch(v: View, event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                lastX = event.rawX.toInt()
                lastY = event.rawY.toInt()
            }
            MotionEvent.ACTION_MOVE -> {
                val dx = event.rawX.toInt() - lastX
                val dy = event.rawY.toInt() - lastY
                params.x -= dx // 因为是RIGHT gravity,x是相对于右边的偏移,所以要减
                params.y += dy
                windowManager.updateViewLayout(floatingView, params)
                lastX = event.rawX.toInt()
                lastY = event.rawY.toInt()
            }
        }
        return true
    }
})

小提示

  • 悬浮层的逻辑建议放在Service里,这样即使App退到后台,悬浮层也能保持显示(当然要注意后台保活的问题)
  • 测试的时候记得在不同Android版本的设备上都跑一遍,避免权限适配问题

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

火山引擎 最新活动