Android应用悬浮按钮如何获取MotionEvent的真实触摸位置
解决Android悬浮按钮拖拽位置偏移问题
不用计算状态栏或导航栏高度,最优方案是记录触摸点相对于悬浮按钮的内部偏移量,通过相对移动来更新位置,完全规避系统栏对坐标的影响。
修改后的代码
val displayMetrics = displayData.getInstance() cursorView = Button(context) val cursorSize = displayMetrics.screenSizeX / 10 cursorView?.setBackgroundResource(R.drawable.cursor) cursorParams = WindowManager.LayoutParams( cursorSize, cursorSize, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, PixelFormat.TRANSLUCENT ) cursorParams?.gravity = Gravity.START or Gravity.TOP cursorParams?.x = (displayMetrics.screenSizeX - cursorSize) / 2 cursorParams?.y = (displayMetrics.screenSizeY - cursorSize) / 2 // 记录触摸点相对于按钮的偏移量 var downX = 0f var downY = 0f cursorView?.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { // 保存触摸点在按钮内的坐标(相对于按钮左上角) downX = event.x downY = event.y true } MotionEvent.ACTION_MOVE -> { // 用屏幕绝对坐标减去偏移量,得到按钮左上角的正确位置 cursorParams?.x = (event.rawX - downX).toInt() cursorParams?.y = (event.rawY - downY).toInt() Tools.logMessage(message = "Screen Size: ${displayMetrics.screenSizeX} x ${displayMetrics.screenSizeY}") Tools.logMessage(message = "Calculated Cursor Position: ${cursorParams?.x}, ${cursorParams?.y}") windowManager.updateViewLayout(cursorView, cursorParams) true } else -> false } } windowManager.addView(cursorView, cursorParams)
关键逻辑说明
- ACTION_DOWN时记录偏移:当用户按下按钮时,用
event.x和event.y获取触摸点相对于按钮自身左上角的坐标,这个偏移量是固定的(只要用户不改变触摸点在按钮上的位置)。 - ACTION_MOVE时计算新位置:用
event.rawX/event.rawY(屏幕绝对坐标)减去之前记录的偏移量,直接得到按钮左上角应该在的屏幕绝对位置,完全不用考虑状态栏、导航栏的存在——因为rawX/rawY是屏幕物理坐标,偏移量是按钮内部的相对坐标,两者相减的结果就是按钮在屏幕上的准确位置。
这种方法的优势:
- 适配所有Android设备,无需额外计算系统栏高度,避免因设备差异(如刘海屏、折叠屏)导致的适配问题。
- 逻辑更简洁,直接通过相对移动实现精准拖拽,不会出现位置偏移。
内容的提问来源于stack exchange,提问作者Droid Automations
相关产品推荐
相关产品推荐

