如何在Android Studio中实现示例图中的右上角悬浮层?
实现Android右上角悬浮Overlay的完整方案
嘿,我刚好折腾过类似的悬浮层功能,给你梳理下核心步骤,照着来就能搞定图里那个右上角的悬浮Overlay啦!
一、先搞定悬浮窗权限
这是第一步也是最关键的,Android对悬浮窗权限管得很严:
- 在
AndroidManifest.xml里先声明权限:<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> - Android 6.0+需要动态判断权限,如果没有的话,引导用户去设置开启:
注意:部分定制ROM(比如小米、华为)的权限逻辑有点特殊,可能需要额外引导用户去对应品牌的权限管理页开启。if (!Settings.canDrawOverlays(context)) { val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.packageName)) startActivityForResult(intent, REQUEST_OVERLAY_PERMISSION) }
二、创建悬浮层布局
你可以用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() }
四、添加悬浮层到屏幕
拿到WindowManager和params后,直接把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




