popwindow实现可拖动+滑到屏幕外+屏幕外回弹

可拖动效果

fun makeDraggable(popupWindow: PopupWindow) {
        popupWindow.contentView.setOnTouchListener(object : View.OnTouchListener {
            var lastX = 0f
            var lastY = 0f
            var isDragging = false
            override fun onTouch(v: View?, event: MotionEvent): Boolean {
                val touchSlop = ViewConfiguration.getTouchSlop() * 2

                when (event.action) {
                    MotionEvent.ACTION_DOWN -> {
                        lastX = event.rawX
                        lastY = event.rawY
                        isDragging = false
                        return isDragging
                    }
                    MotionEvent.ACTION_MOVE -> {
                        val dx = event.rawX - lastX
                        val dy = event.rawY - lastY

                        if (Math.abs(dx) > touchSlop || Math.abs(dy) > touchSlop) {
                            val decorView = popupWindow.contentView.parent as ViewGroup //popwindow的内部变量decorView
                            val lp = decorView.layoutParams as WindowManager.LayoutParams
                            lp.flags = lp.flags or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                            popupWindow.update(lp.x + dx.toInt(), lp.y + dy.toInt(), -1, -1)
                            lastX = event.rawX
                            lastY = event.rawY
                            isDragging = true
                        }
                        return isDragging
                    }
                    MotionEvent.ACTION_UP -> {
                        return isDragging
                    }
                }
                return true
            }

        })
    }

用法很简单,只需要调用
makeDraggable(yourPopupWindow)

支持滑到屏幕外

默认是不允许滑动屏幕外的,要想支持滑到屏幕外也很简单
popupWindow.isClippingEnabled = false

支持屏幕外回弹

当支持滑到屏幕外时候通常都需要有回弹效果,即松手时从屏幕外回弹到屏幕内。
只要在松手时使用属性动画即刻(处理MotionEvent.ACTION_UP 事件)

MotionEvent.ACTION_UP -> {
    ...
    ...

    val supportRollback = true
    if (supportRollback) {
        var tartgetX = 0
        var tartgetY = 0
        val decorView = popupWindow.contentView.parent as ViewGroup //popwindow的内部变量decorView
        val lp = decorView.layoutParams as WindowManager.LayoutParams
        tartgetX = Math.min(Math.max(lp.x, 0), ScreenUtils.getScreenWidth() - popupWindow.width)
        tartgetY = Math.min(Math.max(lp.y, 0), ScreenUtils.getScreenHeight() - popupWindow.height)
        if (tartgetX != lp.x || tartgetY != lp.y) {
            val ofObject = ValueAnimator.ofObject(TypeEvaluator { fraction, startValue, endValue ->
                Point((startValue.x + (endValue.x - startValue.x) * fraction).toInt(),
                        (startValue.y + (endValue.y - startValue.y) * fraction).toInt())
            }, Point(lp.x, lp.y), Point(tartgetX, tartgetY))
            ofObject.addUpdateListener {
                val value = it.animatedValue as Point
                popupWindow.update(value.x, value.y, -1, -1)
            }
            ofObject.interpolator = LinearInterpolator()
            ofObject.start()
        }
    }

   ...
   ...
}

当需要给回弹设置一个边界(默认是手机屏幕四边),只需要改下面两行代码

tartgetX = Math.min(Math.max(lp.x, 0), ScreenUtils.getScreenWidth() - popupWindow.width)//(0代表左边界,ScreenUtils.getScreenWidth()代表右边界)
tartgetY = Math.min(Math.max(lp.y, 0), ScreenUtils.getScreenHeight() - popupWindow.height)//(0代表上边界,ScreenUtils.getScreenWidth()代表下边界)

你可能感兴趣的:(popwindow实现可拖动+滑到屏幕外+屏幕外回弹)