Well after a night of coca cola & debugging I managed to get this to work. I share the solution just in case it is of interest to anyone, because it took me quite a lot of time to get it running.
I didn't manage to get it running with getParent().onRequestDisableInterceptTouch()
, I was close, but couldn't find a way for the child widgets to get the MotionEvents they need for scrolling once I intercepted the touch on the parent, so even though the outer scroll was prevented correctly, the inner widgets didn't scroll.
So the solution is to interceptTouchEvents
in the children ONLY, and if the children is scrollable (known property), and the touch is ACTION_DOWN, then disable the scrollview two levels above. If the touch is ACTION_UP, we enable the scrollview.
To enable/disable the scrollview I just intercept the touch event and with a flag filter the event or not.
I did three auxiliary classes, one for the ScrollView, one for the Container, One for the widgets:
This class wraps every widget and, if I call setNeedsScroll(true) , then touches will be intercepted, and when it is touched, it will (tell the container to) tell the scrollview to disable itself. When the touch is released, it will re-enable the scrollview.
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);
}
}
This is the container, only child of the scrollview
, and holds the different widgets. It just provides methods for the children so they can enable/disable the scroll:
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);
}
}
and finally a scrollview capable of deactivation. It disables the scroll 'old-skool', intercepting and blocking events.
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);
}
}