可拖动效果
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<Point> { 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()代表下边界)