Last active
January 25, 2020 19:33
-
-
Save davidliu/c246a717f00494a6ad237a592a3cea4f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class DelegatingLayout extends FrameLayout { | |
private boolean mIsDelegating; | |
private ViewGroup mDelegateView; | |
private int[] mOriginalOffset = new int[2]; | |
@Override | |
public boolean dispatchTouchEvent(MotionEvent ev) { | |
// Clear delegating flag on touch start/end | |
switch (ev.getAction()) { | |
case MotionEvent.ACTION_DOWN: | |
case MotionEvent.ACTION_UP: | |
case MotionEvent.ACTION_CANCEL: | |
mIsDelegating = false; | |
mOriginalOffset[0] = 0; | |
mOriginalOffset[1] = 0; | |
} | |
// If we're delegating, send all events to the delegate | |
if (mIsDelegating) { | |
// Offset location in case the delegate view has shifted since we last fed it a motion event. | |
ev.offsetLocation(mOriginalOffset[0] - mDelegateView.getLeft(), mOriginalOffset[1] - mDelegateView.getTop()); | |
return mDelegateView.dispatchTouchEvent(ev); | |
} | |
// Check if the delegate wants to steal touches. | |
mIsDelegating = mDelegateView.onInterceptTouchEvent(ev); | |
if (mIsDelegating) { | |
// If delegate has stolen, we should cancel any touch handling in our own view. | |
MotionEvent cancel = MotionEvent.obtain(ev); | |
cancel.setAction(MotionEvent.ACTION_CANCEL); | |
super.dispatchTouchEvent(cancel); | |
cancel.recycle(); | |
// May be more complicated to handle other edge cases | |
// (i.e. non shared parent view descendants, translation, etc.) | |
// | |
// I would use getLocationInWindow to cover more cases, but | |
// the current issue only touches getTop() so this simple efficient solution is fine. | |
mOriginalOffset[0] = mDelegateView.getLeft(); | |
mOriginalOffset[1] = mDelegateView.getTop(); | |
// Send the touch event to the delegate | |
return mDelegateView.onTouchEvent(ev); | |
} | |
// No delegation, handle like usual. | |
return super.dispatchTouchEvent(ev); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Much appreciate it. The
isPointInChildBounds
suggestion (along with the other requirements) is doing the trick just fine, the rest will be a matter of adjusting to each need. Thanks a lot for the great information, this was extremely useful.