正在覆盖与ScrollView竞争的onTouchEvent



从简单的概述来看,我有一个自定义视图,其中包含一些位图,用户可以拖动并调整大小。

我这样做的方式相当标准,因为我在CustomView中覆盖onTouchEvent,并检查用户是否正在触摸图像等。

当我想将此CustomView放置在ScrollView中时,问题就来了。这是有效的,但ScrollView和CustomView似乎在争夺MotionEvents,即当我试图拖动图像时,它要么移动缓慢,要么视图滚动。

我想我可能需要扩展ScrollView,这样我就可以覆盖onInterceptTouchEvent,并让它知道用户是否在图像的范围内,不要尝试滚动。但是,由于ScrollView在层次结构中的位置更高,我如何访问CustomView的当前状态?

有更好的方法吗?

在这种情况下,Android通常使用长按来开始拖动,因为这有助于消除用户打算拖动项目与滚动项目容器的歧义。但是,如果用户开始拖动项目时有一个明确的信号,那么当您知道用户开始拖动时,可以从自定义视图中尝试getParent().requestDisallowInterceptTouchEvent(true)。(此处为该方法的文档。)这将防止ScrollView在当前手势结束之前拦截触摸事件。

没有一个解决方案对我来说是"开箱即用"的,可能是因为我的自定义视图扩展了view,而不是ViewGroup。因此我无法实现onInterceptTouchEvent

调用getParent().requestDisallowInterceptTouchEvent(true)也是抛出NPE,或者什么都不做。

最后,这就是我解决问题的方法:
在您的自定义onTouchEvent中,当您的视图将处理该事件时,请调用requestDisallow...。例如:

@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;
}

现在,我的自定义视图工作正常,可以处理一些事件,并让scrollView捕获我们不关心的事件。在此处找到解决方案:http://android-devblog.blogspot.com.es/2011/01/scrolling-inside-scrollview.html

希望能有所帮助。

有一个名为MotionEvent.ACTION_CANCEL的Android事件(值=3)。我所做的就是覆盖我的自定义控件的onTouchEvent方法并捕获这个值。如果我检测到这种情况,我会做出相应的反应。

这里有一些代码:

@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;
}

相关内容

  • 没有找到相关文章