Android 右滑退出activity简易版

642 阅读1分钟

通过拦截Activity的MotionEvent,然后操作Activity.window.decorView,还需要将window背景设为透明

override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
    return swipeBackAction(ev) || super.dispatchTouchEvent(ev)
}

private var touchX = 0f
private var touchY = 0f
private var touchOriginX = 0f
private var scrolling = false

/**
 * 开启右移退出后,水平的方向的事件都被拦截
 */
private fun swipeBackAction(ev: MotionEvent?): Boolean {
    if (!isSupportSwipeBack) {
        return isSupportSwipeBack
    }

    when (ev?.action) {
        MotionEvent.ACTION_DOWN -> {
            touchX = ev.x
            touchY = ev.y
            touchOriginX = ev.x
        }
        MotionEvent.ACTION_MOVE -> {
            //拦截水平方向的移动
            val moveX = -(ev.x - touchX).toInt()
            val moveY = -(ev.y - touchY).toInt()

            //0 - 0.15 * getScreenWidth() 范围内允许右滑
            val maxTouchX = 0.15 * getScreenWidth()

            if ((abs(ViewConfiguration.get(this).scaledTouchSlop) > abs(moveX) && !scrolling) || touchOriginX > maxTouchX) {
                return false
            }
            touchX = ev.x
            touchY = ev.y
            if (abs(moveY) > abs(moveX) && !scrolling) {
                return false
            }
            scrolling = true
            loge("MotionEvent.ACTION_MOVE   moveX $moveX  touchOriginX $touchOriginX")
            if (ev.x - touchOriginX >= 0) {
                window.decorView.scrollBy(moveX, 0)
            } else {
                window.decorView.scrollTo(0, 0)
            }
            return true
        }
        MotionEvent.ACTION_UP -> {
            //偏移量
            val moveX = ev.x - touchOriginX
            loge(
                "MotionEvent.ACTION_UP   moveX $moveX  touchOriginX $touchOriginX  --- ${ViewConfiguration.get(
                    this
                ).scaledTouchSlop}"
            )
            touchX = 0f
            touchOriginX = 0f
            scrolling = false

            if (abs(ViewConfiguration.get(this).scaledTouchSlop) < abs(moveX)) {
                //水平方向存在滑动
                if (moveX > 0.4 * getScreenWidth()) {
                    //finish
                    val valueObjectAnimator = ValueAnimator.ofFloat(moveX - getScreenWidth())
                        .setDuration(200)
                    valueObjectAnimator.addUpdateListener {
                        val x = it.animatedValue as Float
                        loge("valueObjectAnimator $x")
                        window.decorView.scrollBy(x.toInt(), 0)
                    }
                    valueObjectAnimator.addListener(onEnd = {
                        finish()
                    })
                    valueObjectAnimator.start()
                } else {
                    //rollBack
                    window.decorView.scrollTo(0, 0)
                }
                return true
            } else {
                window.decorView.scrollTo(0, 0)
            }
        }
    }
    return false
}

这个方法最主要的原理就是
1.我们编写的布局都是添加在window.decorView中的
2.根据Activity的事件分发原理,对事件进行分发、消费