Android 自定义可以拖动并自动贴边的viewgroup
class DraggableViewGroup @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
FrameLayout(context, attrs, defStyle) {
private var mViewDragHelper: ViewDragHelper? = null
private var mCurrentTop = 0
private var mCurrentLeft = 0
init {
mViewDragHelper = ViewDragHelper.create(this, 1.0f, object : ViewDragHelper.Callback() {
override fun tryCaptureView(child: View, pointerId: Int): Boolean {
return true
}
override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
val topBound = paddingTop
val bottomBound = height - child.height - paddingBottom
mCurrentTop = top.coerceAtLeast(topBound).coerceAtMost(bottomBound)
return mCurrentTop
}
override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int {
val leftBound = paddingLeft
val rightBound = width - child.width - paddingRight
mCurrentLeft = left.coerceAtLeast(leftBound).coerceAtMost(rightBound)
return mCurrentLeft
}
override fun getViewHorizontalDragRange(child: View): Int {
return measuredWidth - child.measuredWidth
}
override fun getViewVerticalDragRange(child: View): Int {
return measuredHeight - child.measuredHeight
}
override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) {
super.onViewReleased(releasedChild, xvel, yvel)
val childWidth = releasedChild.width
val parentWidth = width
val leftBound = paddingLeft
val rightBound = width - releasedChild.width - paddingRight
if (childWidth / 2 + mCurrentLeft < parentWidth / 2) {
mViewDragHelper?.settleCapturedViewAt(leftBound, mCurrentTop)
} else {
mViewDragHelper?.settleCapturedViewAt(rightBound, mCurrentTop)
}
invalidate()
}
})
}
override fun computeScroll() {
super.computeScroll()
if (mViewDragHelper != null && mViewDragHelper?.continueSettling(true) == true) {
invalidate()
}
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
if (isTouchView(ev.x, ev.y, getChildAt(0))) {
val action = MotionEventCompat.getActionMasked(ev)
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mViewDragHelper?.cancel()
return false
}
return mViewDragHelper?.shouldInterceptTouchEvent(ev) ?: super.onInterceptTouchEvent(ev)
} else {
return super.onInterceptTouchEvent(ev)
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
if (isTouchView(event.x, event.y, getChildAt(0))) {
mViewDragHelper?.processTouchEvent(event)
return true
} else {
return super.onTouchEvent(event)
}
}
private fun isTouchView(downX: Float, downY: Float, view: View): Boolean {
return isTouchView(downX, downY, view.x, view.x + view.width, view.y, view.y + view.height)
}
private fun isTouchView(downX: Float, downY: Float, left: Float, right: Float, top: Float, bottom: Float): Boolean {
return downX > left && downX < right && downY > top && downY < bottom
}
}