I needed to intercept the touch events for a DialogFragment
, so I overrode it's view's parent's onInterceptTouchEvent
like so:
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
ViewGroup viewGroup = new FrameLayout(GlobalState.getContext()){
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
mDecorView.onTouchEvent(ev);
return super.onInterceptTouchEvent(ev);
}
};
View view = inflater.inflate(R.layout.enter_number_dialog_layout,container);
viewGroup.addView(view);
return viewGroup;
}
As you can see, I call mDecorView.onTouchEvent
whenever the fragment is touched. However, the problem is, even though I know interceptOnTouchEvent
is always called when the fragment's layout is touched -- placed a breakpoint on the mDecorView.onTouchEvent
line -- mDecorView
's OnTouchListener.onTouch
is only executed when the TextView
is touched, but not when anything inside the GridLayout
is; which are the only two direct children. I know this because I placed a breakpoint on the first line of code in my implementation of onTouch
, and it's always called when the TextView
is touched, but not when the GridLayout
is.
Here is my fragment's layout:
<TextView
android:id="@+id/number_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:hint="$"
android:singleLine="true"
android:textSize="40sp"/>
<GridLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:columnCount="3"
android:orientation="horizontal">
<Button
android:id="@+id/the_1_button"
android:background="@android:color/white"
android:text="1"/>
<Button
android:id="@+id/the_2_button"
android:background="@android:color/white"
android:text="2"/>
<Button
android:id="@+id/the_3_button"
android:background="@android:color/white"
android:text="3"/>
<Button
android:id="@+id/the_4_button"
android:background="@android:color/white"
android:text="4"/>
<Button
android:id="@+id/the_5_button"
android:background="@android:color/white"
android:text="5"/>
<Button
android:id="@+id/the_6_button"
android:background="@android:color/white"
android:text="6"/>
<Button
android:id="@+id/the_7_button"
android:background="@android:color/white"
android:text="7"/>
<Button
android:id="@+id/the_8_button"
android:background="@android:color/white"
android:text="8"/>
<Button
android:id="@+id/the_9_button"
android:background="@android:color/white"
android:text="9"/>
<ImageButton
android:id="@+id/the_backspace_button"
style="@style/Widget.AppCompat.Button"
android:background="@android:color/white"
android:src="@drawable/ic_backspace"/>
<Button
android:id="@+id/the_0_button"
android:background="@android:color/white"
android:text="0"/>
<Button
android:id="@+id/the_done_button"
android:background="@android:color/white"
android:text="done"/>
</GridLayout>
</LinearLayout>
Any idea why mDecorView
's OnTouchListener.onTouch
is not being called when the GridLayout
is touched?
Here is the body of mDecorView
's OnTouchListener
's onTouch()
:
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// offset because the view is translated during swipe
motionEvent.offsetLocation(mTranslationX, 0);
if (mViewWidth < 2) {
mViewWidth = mView.getWidth();
}
switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
// TODO: ensure this is a finger, and set a flag
mDownX = motionEvent.getRawX();
mDownY = motionEvent.getRawY();
if (mCallbacks.canDismiss(mToken)) {
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(motionEvent);
}
break;
}
case MotionEvent.ACTION_UP: {
if (mVelocityTracker == null) {
break;
}
float deltaX = motionEvent.getRawX() - mDownX;
mVelocityTracker.addMovement(motionEvent);
mVelocityTracker.computeCurrentVelocity(1000);
float velocityX = mVelocityTracker.getXVelocity();
float absVelocityX = Math.abs(velocityX);
float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
boolean dismiss = false;
boolean dismissRight = false;
if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
dismiss = true;
dismissRight = deltaX > 0;
} else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
&& absVelocityY < absVelocityX
&& absVelocityY < absVelocityX && mSwiping) {
// dismiss only if flinging in the same direction as dragging
dismiss = (velocityX < 0) == (deltaX < 0);
dismissRight = mVelocityTracker.getXVelocity() > 0;
}
if (dismiss) {
// dismiss
mView.animate()
.translationX(dismissRight ? mViewWidth : -mViewWidth)
.alpha(0)
.setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
performDismiss();
}
});
return true;
} else if (mSwiping) {
// cancel
mView.animate()
.translationX(0)
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
}
mVelocityTracker.recycle();
mVelocityTracker = null;
mTranslationX = 0;
mDownX = 0;
mDownY = 0;
mSwiping = false;
break;
}
case MotionEvent.ACTION_CANCEL: {
if (mVelocityTracker == null) {
break;
}
mView.animate()
.translationX(0)
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
mVelocityTracker.recycle();
mVelocityTracker = null;
mTranslationX = 0;
mDownX = 0;
mDownY = 0;
mSwiping = false;
break;
}
case MotionEvent.ACTION_MOVE: {
if (mVelocityTracker == null) {
break;
}
mVelocityTracker.addMovement(motionEvent);
float deltaX = motionEvent.getRawX() - mDownX;
float deltaY = motionEvent.getRawY() - mDownY;
if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
mSwiping = true;
mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
mView.getParent().requestDisallowInterceptTouchEvent(true);
// Cancel listview's touch
MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
(motionEvent.getActionIndex() <<
MotionEvent.ACTION_POINTER_INDEX_SHIFT));
mView.onTouchEvent(cancelEvent);
cancelEvent.recycle();
}
if (mSwiping) {
mTranslationX = deltaX;
mView.setTranslationX(deltaX - mSwipingSlop);
// TODO: use an ease-out interpolator or such
mView.setAlpha(Math.max(0f, Math.min(1f,
1f - 2f * Math.abs(deltaX) / mViewWidth)));
return true;
}
break;
}
}
return false;
}
Callback methods are designed to be called by the event handling system, not by your own code. When events share functionality, it is best to put the common code in a method which can be called by any callback method. This is preferable to calling a callback directly yourself because you have more control. You know exactly when the method will execute and you can accept only parameters which are meaningful to the task at hand.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.