从简单的概述我有一个自定义视图,其中包含用户可以拖动并调整大小的一些位图。
我这样做的方式是相当标准的,因为我在我的CustomView中重写onTouchEvent并检查用户是否在图像中触摸等。
当我想将此CustomView放在ScrollView中时,我的问题出现了。这可行,但ScrollView和CustomView似乎竞争MotionEvents,即当我尝试拖动图像时,它会缓慢移动或视图滚动。
我想我可能需要扩展ScrollView,以便我可以覆盖onInterceptTouchEvent并让它知道用户是否在图像的范围内而不是尝试滚动。但是,因为ScrollView在层次结构中更高,我将如何访问CustomView的当前状态?
有更好的方法吗?
答案 0 :(得分:40)
正常情况下,Android会使用长按来开始拖动这类情况,因为它有助于消除用户打算拖动项目时的歧义,而不是滚动项目的容器。但是,如果您在用户开始拖动项目时有明确的信号,请在知道用户开始拖动时从自定义视图中尝试getParent().requestDisallowInterceptTouchEvent(true)
。 (此方法的文档here。)这将阻止ScrollView拦截触摸事件,直到当前手势结束。
答案 1 :(得分:8)
找不到任何解决方案对我来说都是“开箱即用”,可能是因为我的自定义视图扩展了查看,而不是 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
希望它有所帮助。
答案 2 :(得分:0)
有一个名为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;
}