如何正确创建可拖动悬浮视图?解决首次触摸偏移问题
修复浮动视图首次触摸跳转问题
问题根源在于你在ACTION_DOWN时错误使用了moveIcon的相对坐标(view.x/view.y)计算触摸偏移,而浮动视图的实际位置由WindowManager.LayoutParams的x/y控制,二者并不等价,导致首次触摸时计算出的目标位置错误。
以下是修复后的完整代码:
private lateinit var windowManager: WindowManager private var floatingView: View? = null private var moveIcon: View? = null // 新增变量记录初始触摸坐标和视图当前位置 private var initialRawX = 0f private var initialRawY = 0f private var currentLayoutX = 0 private var currentLayoutY = 0 // 初始化浮动视图的代码 fun initFloatingView() { windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager val layoutInflater = LayoutInflater.from(this) floatingView = layoutInflater.inflate(R.layout.floating_layout, null) val params = WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { @Suppress("DEPRECATION") WindowManager.LayoutParams.TYPE_PHONE }, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT ) // 可选:设置初始位置,比如屏幕右下角(需先测量视图尺寸) // floatingView?.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) // params.x = resources.displayMetrics.widthPixels - floatingView!!.measuredWidth // params.y = resources.displayMetrics.heightPixels - floatingView!!.measuredHeight windowManager.addView(floatingView, params) moveIcon = floatingView!!.findViewById(R.id.moveIcon) moveIcon.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { // 获取浮动视图当前的布局参数 val layoutParams = floatingView!!.layoutParams as WindowManager.LayoutParams // 记录视图当前的实际位置 currentLayoutX = layoutParams.x currentLayoutY = layoutParams.y // 记录触摸点的绝对屏幕坐标 initialRawX = event.rawX initialRawY = event.rawY } MotionEvent.ACTION_MOVE -> { // 计算触摸移动的偏移量 val deltaX = (event.rawX - initialRawX).toInt() val deltaY = (event.rawY - initialRawY).toInt() // 计算新位置:当前位置 + 触摸偏移量 val newX = currentLayoutX + deltaX val newY = currentLayoutY + deltaY updatePosition(newX, newY) } } true } } private fun updatePosition(x: Int, y: Int) { val layoutParams = floatingView!!.layoutParams as WindowManager.LayoutParams layoutParams.x = x layoutParams.y = y windowManager.updateViewLayout(floatingView, layoutParams) }
关键修复点:
- 移除基于
moveIcon相对坐标的偏移计算,改为直接记录浮动视图的实际位置(layoutParams.x/y)和触摸点的绝对屏幕坐标 - 在
ACTION_MOVE时,通过触摸点的偏移量叠加到视图当前位置,确保拖动过程平滑无跳转
内容的提问来源于stack exchange,提问作者user19763422
相关产品推荐
相关产品推荐

