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()代表下边界)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 179,472评论 25 708
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 14,173评论 2 59
  • 一个个圆滚滚 有点调皮 又很规矩 挤挤挨挨 你压着我 我踩着你 手足情深 本是同根 鼓鼓囊囊 低垂着头 自信而不张...
    梦之芬芳阅读 315评论 0 0
  • 引言 代码格式决定读者对代码质量最初的判断。好的格式能够增强代码的可读性,并且能让读者阅读代码的时候心情愉悦。 ...
    前进中的奋斗猿阅读 602评论 0 1
  • (一) 老屋残墙无影踪,高楼庭院绿荫浓。 农民种地四时乐,机械耕耘五谷丰。 妇幼猎奇开电脑,亲朋问候拨联通。 客来...
    果苗儿阅读 644评论 0 1

友情链接更多精彩内容