@@ -31,6 +31,7 @@ import com.google.android.material.shape.MaterialShapeDrawable
3131import com.itsaky.androidide.R
3232import kotlin.math.max
3333import kotlin.math.min
34+ import androidx.core.content.withStyledAttributes
3435
3536/* *
3637 * A layout which can be dragged vertically to reveal a hidden content.
@@ -67,14 +68,22 @@ open class SwipeRevealLayout @JvmOverloads constructor(
6768 private var rightDragProgress = 0f
6869 private var isVerticalDragEnabled = true
6970
71+ private var isDownInDragHandle = false
72+ /* *
73+ * Whether the most recent touch-down landed within the configured drag handle. The vertical
74+ * drag-to-reveal gesture is only captured when this is `true`, so that scroll gestures starting
75+ * in the middle of the overlapping content (e.g. the editor) are not stolen.
76+ */
77+ private val dragHandleLocation = IntArray (2 )
78+
7079 init {
7180 leftDragHelper = ViewDragHelper .create(this , 1f , LeftDragCallback ())
7281 rightDragHelper = ViewDragHelper .create(this , 1f , RightDragCallback ())
7382 }
7483
7584 private val dragHelperCallback = object : ViewDragHelper .Callback () {
7685 override fun tryCaptureView (child : View , pointerId : Int ): Boolean {
77- return isVerticalDragEnabled && child == = overlappingContent
86+ return isVerticalDragEnabled && isDownInDragHandle && child == = overlappingContent
7887 }
7988
8089 override fun onViewPositionChanged (changedView : View , left : Int , top : Int , dx : Int , dy : Int ) {
@@ -193,11 +202,15 @@ open class SwipeRevealLayout @JvmOverloads constructor(
193202
194203 init {
195204 if (attrs != null ) {
196- val typedArray = context.obtainStyledAttributes(attrs, R .styleable.SwipeRevealLayout ,
197- defStyleAttr, defStyleRes)
198- dragHandleViewId = typedArray.getResourceId(R .styleable.SwipeRevealLayout_dragHandle ,
199- dragHandleViewId)
200- typedArray.recycle()
205+ context.withStyledAttributes(
206+ attrs, R .styleable.SwipeRevealLayout ,
207+ defStyleAttr, defStyleRes
208+ ) {
209+ dragHandleViewId = getResourceId(
210+ R .styleable.SwipeRevealLayout_dragHandle ,
211+ dragHandleViewId
212+ )
213+ }
201214 }
202215 }
203216
@@ -237,6 +250,9 @@ open class SwipeRevealLayout @JvmOverloads constructor(
237250 dragHelper.cancel()
238251 return false
239252 }
253+ if (action == MotionEvent .ACTION_DOWN ) {
254+ isDownInDragHandle = isTouchInDragHandle(ev)
255+ }
240256 val isLeft = leftDragHelper.shouldInterceptTouchEvent(ev)
241257 val isRight = rightDragHelper.shouldInterceptTouchEvent(ev)
242258 val isVertical = dragHelper.shouldInterceptTouchEvent(ev)
@@ -251,6 +267,31 @@ open class SwipeRevealLayout @JvmOverloads constructor(
251267 return true
252268 }
253269
270+ /* *
271+ * Returns whether the given touch event falls within the bounds of the configured drag handle
272+ * (see [dragHandleViewId] / the `app:dragHandle` attribute). When no drag handle is configured,
273+ * the whole overlapping content acts as the handle (legacy behavior).
274+ */
275+ private fun isTouchInDragHandle (ev : MotionEvent ): Boolean {
276+ if (dragHandleViewId == 0 ) {
277+ return true
278+ }
279+
280+ val handle = findViewById<View >(dragHandleViewId)
281+ if (handle == null || handle.visibility != VISIBLE ) {
282+ return false
283+ }
284+
285+ handle.getLocationOnScreen(dragHandleLocation)
286+ val left = dragHandleLocation[0 ]
287+ val top = dragHandleLocation[1 ]
288+ val right = left + handle.width
289+ val bottom = top + handle.height
290+ val x = ev.rawX
291+ val y = ev.rawY
292+ return x >= left && x <= right && y >= top && y <= bottom
293+ }
294+
254295 override fun computeScroll () {
255296 if (leftDragHelper.continueSettling(true ) or rightDragHelper.continueSettling(true ) or dragHelper.continueSettling(true )) {
256297 postInvalidateOnAnimation()
0 commit comments