我使用以下代码在屏幕上拖动视图,它可以工作。但是,当用户第一次触摸
moveIcon
时,floatingView
突然移动到屏幕中心,即使我希望它保持在原来的位置。我怎样才能解决这个问题?我怀疑问题出在 updatePosition() 方法中。
windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
val layoutInflater = LayoutInflater.from(this)
floatingView = layoutInflater.inflate(R.layout.floating_layout, null)
// Set up the layout parameters for the floating view
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
)
windowManager!!.addView(floatingView, params)
// Moving the views:
moveIcon = floatingView!!.findViewById(R.id.moveIcon)
moveIcon.setOnTouchListener { view, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
// Save the initial touch coordinates relative to the moveIcon view
initialTouchX = event.rawX - view.x
initialTouchY = event.rawY - view.y
}
MotionEvent.ACTION_MOVE -> {
// Calculate the new position based on the movement and initial touch coordinates
val newX = event.rawX - initialTouchX
val newY = event.rawY - initialTouchY
updatePosition(newX.toInt(), newY.toInt())
}
}
true
}
}
private fun updatePosition(x: Int, y: Int) {
val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
val layoutParams = floatingView!!.layoutParams as WindowManager.LayoutParams
layoutParams.x = x
layoutParams.y = y
windowManager.updateViewLayout(floatingView, layoutParams)
}
视图的 X/Y 坐标在 documentation 中定义为
translationX/Y
加 current left/top
属性。视图的 Left/Top 位置是相对于其父视图的。
但是,你的
floatingView
是直接通过WindowManger
添加的;它的父级是 ViewRootImpl
。因此,您不会期望该视图的左侧/顶部位置具有您需要的真实值,因为 ViewRootImpl
是开发人员无法访问的系统范围根视图;因此,如果您登录 view.x/y
,您将始终看到它们 0
。
他们没有直接从视图访问
ViewRootImpl
,而是为此提供了 WindowManger
API。即,当 floatingView
添加到 ViewRootImpl
时;我们没有做ViewRootImpl.addView()
,但我们做了windowManager.addView()
。
同样,我们需要通过
WindowManager
获取 x/y 参数,并使用 WindowManager.LayoutParams
来获取正确的值:
....
MotionEvent.ACTION_DOWN -> {
// initialTouchX = event.rawX - view.x // Remove this
// initialTouchY = event.rawY - view.y // Remove this
(floatingView.layoutParams as WindowManager.LayoutParams).let { params ->
initialTouchX = event.rawX - params.x
initialTouchY = event.rawY - params.y
}
}