笔记 android悬浮窗的拖动实现踩坑

想要实现一个可拖动的悬浮窗,原理上非常简单:根据action_move时的event坐标偏移,去修改view的位置即可。
但是实际实现上踩了个小坑。

详细踩坑:

平时获取event的坐标,都是用event.getX() 和 event.getY() ,但是实操下来发现,这样会导致拖动效果不跟手, 拖动的位置比手势移动的位置要小,并且会有明显的位置抖动。

在这个拖动的场景下,其实应该使用 event.getRawX() 和 event.getRawY() 来获取坐标。

event.getX() 和 event.getRawX() 的区别:

    /**
     * {@link #getX(int)} for the first pointer index (may be an
     * arbitrary pointer identifier).
     *
     * @see #AXIS_X
     */
    public final float getX() {
        return nativeGetAxisValue(mNativePtr, AXIS_X, 0, HISTORY_CURRENT);
    }
    /**
     * Returns the original raw X coordinate of this event.  For touch
     * events on the screen, this is the original location of the event
     * on the screen, before it had been adjusted for the containing window
     * and views.
     *
     * @see #getX(int)
     * @see #AXIS_X
     */
    public final float getRawX() {
        return nativeGetRawAxisValue(mNativePtr, AXIS_X, 0, HISTORY_CURRENT);
    }

getRawX()使用的是相对屏幕的坐标,而 getX()使用的是相对view的坐标,在view本身随手势移动的时候,这个相对view的坐标就会发生错误的偏移,导致拖动效果不跟手。

实际代码

binding.root.setOnTouchListener(object : View.OnTouchListener {
                var xDown = 0f
                var yDown = 0f

                var interactorTranslationXWhenDown = 0f
                var interactorTranslationYWhenDown = 0f

                override fun onTouch(v: View?, event: MotionEvent): Boolean {
                    when (event.action) {
                        MotionEvent.ACTION_DOWN -> {
                            xDown = event.rawX
                            yDown = event.rawY
                            interactorTranslationXWhenDown = interactorTranslationX
                            interactorTranslationYWhenDown = interactorTranslationY
                        }
                        MotionEvent.ACTION_MOVE -> {
                            val dx = event.rawX - xDown
                            val dy = event.rawY - yDown
                            interactorTranslationX =
                                interactorTranslationXWhenDown + dx
                            interactorTranslationY =
                                interactorTranslationYWhenDown + dy
                            Timber.e("dx:${dx} dy:${dy}")
                            updateTranslation()
                        }
                        else -> {}
                    }
                    return false
                }

            })

注:如果想写的简单一点,也可以直接使用

interactorTranslationX = event.rawX
interactorTranslationY = event.rawY

这样也能实现基本的拖动效果,只是view会跳到手指右下角的位置来拖动,有点难用。

你可能感兴趣的:(Android,常用代码,技术,android)