开发者

Overriding onTouchEvent competing with ScrollView

开发者 https://www.devze.com 2023-03-10 01:20 出处:网络
From a simplistic overview I have a custom View that contains some bitmaps the user can drag around and resize.

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?


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.


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.


There is an Android event called MotionEvent.ACTION_CANCEL (value = 3). All I do is override my custom control's onTouchEvent method and capture this value. If I detect this condition then I respond accordingly.

Here is some code:

@Override
public boolean onTouchEvent(MotionEvent event) {
    if(isTouchable) {
        int maskedAction = event.getActionMasked();         
        if (maskedAction == MotionEvent.ACTION_DOWN) {
            this.setTextColor(resources.getColor(R.color.octane_orange));
            initialClick = event.getX();
        } else if (maskedAction == MotionEvent.ACTION_UP) {
            this.setTextColor(defaultTextColor);
            endingClick = event.getX();
            checkIfSwipeOrClick(initialClick, endingClick, range);
        } else if(maskedAction == MotionEvent.ACTION_CANCEL)
            this.setTextColor(defaultTextColor);
    }
    return true;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消