user1438128
user1438128

Reputation: 533

OnTouchEvent not working on child views

I have a Linear Layout that has a Button and a TextView on it. I have written a OnTouchEvent for the activity. The code works fine if I touch on the screen, but if I touch the button the code does not work. What is the possible solution for this?

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


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


   break;
   }
   return true;

  }

Upvotes: 33

Views: 28881

Answers (7)

Ray Hulha
Ray Hulha

Reputation: 11231

RecyclerView list_view = findViewById(R.id.list_view);
list_view.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener(){
    @Override
    public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
        View child = rv.findChildViewUnder(e.getX(), e.getY());
        Log.i("Hello", "World");
        return false;
    }
});

Upvotes: 0

Asad
Asad

Reputation: 1439

use public boolean dispatchTouchEvent(MotionEvent event) instead on onTouchEvent()

Upvotes: -1

amdev
amdev

Reputation: 31

you can also try onUserInteraction():

@Override 
public void onUserInteraction(){
     //your code here
     super.onUserInteraction();
}

works well for me!

Upvotes: 0

pierrotlefou
pierrotlefou

Reputation: 40801

Activity::onTouchEvent will be called only when non of the views in the Activity WIndow consumes/handles the event. If you touch the Button, the Button will consume the events, so the Activity won't be able to handle it.

Check out following articles for more about Android Touch Event handling pipeline.

http://pierrchen.blogspot.jp/2014/03/pipeline-of-android-touch-event-handling.html

Upvotes: 0

kouretinho
kouretinho

Reputation: 2260

Let me add one more comment to this excellent post by @Devunwired.

If you've also set an onTouchListener on your View, then its onTouch() method will be called AFTER the dispatch methods, but BEFORE any onTouchEvent() method, i.e. in between no.3 and no.4 on @Devunwired's answer.

Upvotes: 4

devunwired
devunwired

Reputation: 63303

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

Upvotes: 110

Jokahero
Jokahero

Reputation: 1074

Try to set the descendantFocusability attribute of your layout to blocksDescendants

Upvotes: 2

Related Questions