效果图
Screen_recording_20240710_075918.gif
代码实现
class CustomDragView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0,
) : FrameLayout(context, attrs, defStyleAttr) {
lateinit var mFrontChild: View
lateinit var mBackChild: View
private var mFrontChildHeight = 0
private var mTop = 0
private var mDownY = 0f
private var mIsMenuOpen = false
private var mVhCb = object : ViewDragHelper.Callback() {
override fun tryCaptureView(child: View, pointerId: Int): Boolean {
return child == mBackChild
}
override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
Log.i(TAG, "top:$top,dy:$dy")
mTop = top
return if (top > mFrontChildHeight) mFrontChildHeight else if (top < 0) 0 else top
}
override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) {
super.onViewReleased(releasedChild, xvel, yvel)
Log.i(TAG, "yvel:$yvel")
if (releasedChild == mBackChild) {
mIsMenuOpen = mTop > mFrontChildHeight / 3
mVH.settleCapturedViewAt(0, if (mIsMenuOpen) mFrontChildHeight else 0)
invalidate()
}
}
}
override fun computeScroll() {
if (mVH.continueSettling(true)) {
invalidate()
}
}
private var mVH: ViewDragHelper = ViewDragHelper.create(this, mVhCb)
override fun onFinishInflate() {
super.onFinishInflate()
if (childCount > 2) {
throw RuntimeException("only allow two direct children")
}
mFrontChild = getChildAt(0)
mBackChild = getChildAt(1)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
if (changed) {
mFrontChildHeight = mFrontChild.measuredHeight
Log.i(TAG, "frontChildHeight:$mFrontChildHeight")
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
mVH.processTouchEvent(event)
return true
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
//一旦菜单打开全部拦截不给listview处理
if (mIsMenuOpen) {
return true
}
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
//down事件传递给ViewDragHelper
mVH.processTouchEvent(ev)
mDownY = ev.y
}
MotionEvent.ACTION_MOVE -> {
val diffY = ev.y - mDownY
Log.d(TAG, "diff:$diffY")
if (diffY > 0 && !canScrollUp()) {
return true
}
}
}
//事件分发给child
return super.onInterceptTouchEvent(ev)
}
private fun canScrollUp(): Boolean {
var result = false
if (mBackChild is AbsListView) {
val listView = (mBackChild as AbsListView)
result = listView.childCount > 0 && listView.firstVisiblePosition > 0
}
val result2 = mBackChild.canScrollVertically(-1)
Log.i(TAG, "result:$result,result2:$result2")
return result2 || result
}
companion object {
private const val TAG = "CustomDragView"
}
}
代码地址
https://github.com/treech/MyView