Overriding onTouchEvent competing with ScrollView

18,790

Solution 1

Normally Android uses a long press to begin a drag in cases like these since it helps disambiguate when the user intends to drag an item vs. scroll the item's container. But if you have an unambiguous signal when the user begins dragging an item, try getParent().requestDisallowInterceptTouchEvent(true) from the custom view when you know the user is beginning a drag. (Docs for this method here.) This will prevent the ScrollView from intercepting touch events until the end of the current gesture.

Solution 2

None of the solutions found worked "out of the box" for me, probably because my custom view extends View, not ViewGroup, and thus I can't implement onInterceptTouchEvent.

Also calling getParent().requestDisallowInterceptTouchEvent(true) was throwing NPE, or doing nothing at all.

Finally this is how I solved the problem:
Inside your custom onTouchEvent call requestDisallow... when your view will take care of the event. For example:

@Override
public boolean onTouchEvent(MotionEvent event) {
    Point pt = new Point( (int)event.getX(), (int)event.getY() );
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        if (/*this is an interesting event my View will handle*/) {
            // here is the fix! now without NPE
            if (getParent() != null) {
                getParent().requestDisallowInterceptTouchEvent(true);
            }

            clicked_on_image = true;
        }
    } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
        if (clicked_on_image) {
            //do stuff, drag the image or whatever
        }
    } else if (event.getAction() == MotionEvent.ACTION_UP) {
        clicked_on_image = false;
    }
    return true;
}

Now my custom view works fine, handling some events and letting scrollView catch the ones we don't care about. Found the solution here: http://android-devblog.blogspot.com.es/2011/01/scrolling-inside-scrollview.html

Hope it helps.

Share:
18,790

Related videos on Youtube

brk3
Author by

brk3

Updated on June 04, 2022

Comments

  • brk3
    brk3 almost 2 years

    From a simplistic overview I have a custom View that contains some bitmaps the user can drag around and resize.

    The way I do this is fairly standard as in I override onTouchEvent in my CustomView and check if the user is touching within an image, etc.

    My problem comes when I want to place this CustomView in a ScrollView. This works, but the ScrollView and the CustomView seem to compete for MotionEvents, i.e. when I try to drag an image it either moves sluggishly or the view scrolls.

    I'm thinking I may have to extend a ScrollView so I can override onInterceptTouchEvent and let it know if the user is within the bounds of an image not to try and scroll. But then because the ScrollView is higher up in the hierarchy how would I get access to the CustomView's current state?

    Is there a better way?

    • Nadewad
      Nadewad almost 13 years
      I think that your custom view should implement onInterceptTouchEvent and not the scrollview in order to decide if it should handle the touch event accordingly and then hands off the event if it decides not to handle it.
  • brk3
    brk3 almost 13 years
    Thank you so much, that worked! There is some great api knowledge here on SO :)
  • adamp
    adamp almost 13 years
    It helps when you have the people maintaining these things in the platform itself answering your questions. ;)
  • Kevin Duong
    Kevin Duong over 11 years
    @brk3 what's your solution? I have the same issue, can you show your source code? I use long touch but it's not easy to use
  • netzpurist
    netzpurist over 9 years
    Awesome answer, that helped! :) But I suggest to change the NullPointer check to: ViewParent parent = getParent(); if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); }
  • Stony
    Stony about 9 years
    Solved my problems, Thanks.
  • Leonid Ustenko
    Leonid Ustenko almost 7 years
    Wow thanks. I would have discovered this for ages if hadn't found this