Ontouchevent Not Working on Child Views

OnTouchEvent not working on child views

The problem is the order of operations for how Android handles touch events. Each touch event follows the pattern of (simplified example):

  1. Activity.dispatchTouchEvent()
  2. ViewGroup.dispatchTouchEvent()
  3. View.dispatchTouchEvent()
  4. View.onTouchEvent()
  5. ViewGroup.onTouchEvent()
  6. Activity.onTouchEvent()

But events only follow the chain until they are consumed (meaning somebody returns true from onTouchEvent() or a listener). In the case where you just touch somewhere on the screen, nobody is interested in the event, so it flows all the way down to your code. However, in the case of a button (or other clickable View) it consumes the touch event because it is interested in it, so the flow stops at Line 4.

If you want to monitor all touches that go into your Activity, you need to override dispatchTouchEvent() since that what always gets called first, onTouchEvent() for an Activity gets called last, and only if nobody else captured the event. Be careful to not consume events here, though, or the child views will never get them and your buttons won't be clickable.

public boolean dispatchTouchEvent(MotionEvent event) {
int eventaction=event.getAction();

switch(eventaction) {
case MotionEvent.ACTION_MOVE:
reg.setText("hey");
break;
default:
break;
}

return super.dispatchTouchEvent(event);
}

Another option would be to put your touch handling code into a custom ViewGroup (like LinearLayout) and use its onInterceptTouchEvent() method to allow the parent view to steal away and handle touch events when necessary. Be careful though, as this interaction is one that cannot be undone until a new touch event begins (once you steal one event, you steal them all).

HTH

Method onTouchEvent not being called

I found a perfect solution. I implemented new method:

@Override
public boolean dispatchTouchEvent(MotionEvent event) {

View v = getCurrentFocus();
boolean ret = super.dispatchTouchEvent(event);

and now it all works fine!

Edit:

My final code:

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
View v = getCurrentFocus();
if (v instanceof EditText) {
View w = getCurrentFocus();
int scrcoords[] = new int[2];
w.getLocationOnScreen(scrcoords);
float x = event.getRawX() + w.getLeft() - scrcoords[0];
float y = event.getRawY() + w.getTop() - scrcoords[1];
if (event.getAction() == MotionEvent.ACTION_UP
&& (x < w.getLeft() || x >= w.getRight() || y < w.getTop() || y > w
.getBottom())) {

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindow().getCurrentFocus()
.getWindowToken(), 0);
}
}
boolean ret = super.dispatchTouchEvent(event);
return ret;
}

Android onInterceptTouchEvent doesn't get action when have child view

The solution relates to this answer, as it is a result of the standard MotionEvent handling.

In my code, when I touch the child LinearLayout, the parent CustomViewGroup doesn't intercept the MotionEvent as it returns false, but my child LinearLayout doesn't consume the MotionEvent either, so the MotionEvent is returned to the parent's onTouchEvent, not onInterceptTouchEvent.

On the other hand, when I touch my child ScrollView, it consumes the MotionEvent whether scrolling is enabled or disabled.

==> I think because Android doesn't generate a MotionEvent again until the original one is either consumed or finished, so the parent CustomViewGroup doesn't get the ACTION_MOVE MotionEvent via onInterceptTouchEvent, instaed it is piped to onTouchEvent when a child doesn't consume the MotionEvent.

I found two solutions

Solution one

Forcibly make my LinearLayout consume the MotionEvent. This solution is available only when the child LinearLayout has no touchable View, ViewGroup or Widget. Like this:

LinearLayout mLinearLayout = (LinearLayout)findViewById(R.id.child_linear);
mLinearLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});

Solution two

Process the MotionEvent returning from a child in my CustomViewGroup's onTouchEvent. Like this: (Just add else if case in onTouchEvent).

case MotionEvent.ACTION_MOVE: {
if (mIsBeingDragged) {
mLastMotionY = event.getY();
mLastMotionX = event.getX();
pullEvent();
return true;
}
else if (isReadyForPull()) {
final float y = event.getY(), x = event.getX();
final float diff, oppositeDiff, absDiff;
diff = y - mLastMotionY;
oppositeDiff = x - mLastMotionX;
absDiff = Math.abs(diff);
ViewConfiguration config = ViewConfiguration.get(getContext());

if (absDiff > config.getScaledTouchSlop() && absDiff >
Math.abs(oppositeDiff) && diff >= 1f) {
mLastMotionY = y;
mLastMotionX = x;
mIsBeingDragged = true;
}
}
break;
}

While solution 1 is a quick fix for certain situations, solution two is the most flexible and reliable.



Related Topics



Leave a reply



Submit