经过一夜的可口可乐和调试后,我设法让它工作了。我分享这个解决方案以防万一有人感兴趣,因为我花了很多时间才让它运行起来。
我没有设法让它与getParent().onRequestDisableInterceptTouch() 一起运行,我很接近,但是一旦我截获了对父级的触摸,就无法找到让子小部件获得滚动所需的 MotionEvents 的方法,所以即使正确阻止了外部滚动,内部小部件也没有滚动。
所以解决方法是interceptTouchEventsin the children ONLY,并且如果children是可滚动的(已知属性),并且触摸是ACTION_DOWN,则禁用上面两级的scrollview。如果触摸是 ACTION_UP,我们启用滚动视图。
要启用/禁用滚动视图,我只需拦截触摸事件并使用标志过滤事件。
我做了三个辅助类,一个给ScrollView,一个给Container,一个给widgets:
这个类包装了每个小部件,如果我调用 setNeedsScroll(true) ,那么触摸将被拦截,当它被触摸时,它会(告诉容器)告诉滚动视图禁用自身。当触摸被释放时,它将重新启用滚动视图。
class WidgetWrapperLayout extends FrameLayout {
private boolean mNeedsScroll=false;
public WidgetWrapperLayout(Context context) {
super(context);
}
/** Called anytime, ie, during construction, to indicate that this
* widget uses vertical scroll, so we need to disable its container scroll
*/
public void setNeedsScroll(boolean needsScroll) {
mNeedsScroll=needsScroll;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mNeedsScroll) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
((SlideLayout)getParent()).setEnableScroll(false);
break;
case MotionEvent.ACTION_UP:
((SlideLayout)getParent()).setEnableScroll(true);
break;
}
return false;
}
return super.onInterceptTouchEvent(ev);
}
}
这是容器,是scrollview 的唯一子容器,它包含不同的小部件。它只是为孩子提供方法,以便他们可以启用/禁用滚动:
public class ContainerLayout extends FrameLayout {
public ContainerLayout(Context context) {
super(context);
}
public void setEnableScroll(boolean status) {
if (Conf.LOG_ON) Log.d(TAG, "Request enable scroll: "+status);
((StoppableScrollView)getParent()).setScrollEnabled(status);
}
}
最后是一个可以停用的滚动视图。它禁用滚动'old-skool',拦截和阻止事件。
public class StoppableScrollView extends ScrollView {
private String TAG="StoppableScrollView";
private boolean mDisableScrolling=false;
public StoppableScrollView(Context context) {
super(context);
}
/** Enables or disables ScrollView scroll */
public void setScrollEnabled (boolean status) {
if (Conf.LOG_ON) Log.d(TAG, "Scroll Enabled "+status);
mDisableScrolling=!status;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mDisableScrolling) return false;
return super.onInterceptTouchEvent(ev);
}
}