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<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()代表下邊界)