Единственный способ создать такой перехватчик - использовать пользовательский макет ViewGroup.
Но реализации ViewGroup.onInterceptTouchEvent () просто недостаточно в любом случае, потому что дочерние представления могут вызывать ViewParent.requestDisallowInterceptTouchEvent () , и если это делает дочерний вид, ваш вид перестанет получать вызовы interceptTouchEvent (см. здесь для примера, когда вы можете это сделать, когда я ребенок).
Вот класс, который я написал и использую, когда мне нужно что-то подобное, это пользовательский FrameLayout, который дает полный контроль над событиями касания в любом делегаторе
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;
/**
* A FrameLayout that allow setting a delegate for intercept touch event
*/
public class InterceptTouchFrameLayout extends FrameLayout {
private boolean mDisallowIntercept;
public interface OnInterceptTouchEventListener {
/**
* If disallowIntercept is true the touch event can't be stealed and the return value is ignored.
* @see android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)
*/
boolean onInterceptTouchEvent(InterceptTouchFrameLayout view, MotionEvent ev, boolean disallowIntercept);
/**
* @see android.view.View#onTouchEvent(android.view.MotionEvent)
*/
boolean onTouchEvent(InterceptTouchFrameLayout view, MotionEvent event);
}
private static final class DummyInterceptTouchEventListener implements OnInterceptTouchEventListener {
@Override
public boolean onInterceptTouchEvent(InterceptTouchFrameLayout view, MotionEvent ev, boolean disallowIntercept) {
return false;
}
@Override
public boolean onTouchEvent(InterceptTouchFrameLayout view, MotionEvent event) {
return false;
}
}
private static final OnInterceptTouchEventListener DUMMY_LISTENER = new DummyInterceptTouchEventListener();
private OnInterceptTouchEventListener mInterceptTouchEventListener = DUMMY_LISTENER;
public InterceptTouchFrameLayout(Context context) {
super(context);
}
public InterceptTouchFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public InterceptTouchFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public InterceptTouchFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyle) {
super(context, attrs, defStyleAttr, defStyle);
}
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
getParent().requestDisallowInterceptTouchEvent(disallowIntercept);
mDisallowIntercept = disallowIntercept;
}
public void setOnInterceptTouchEventListener(OnInterceptTouchEventListener interceptTouchEventListener) {
mInterceptTouchEventListener = interceptTouchEventListener != null ? interceptTouchEventListener : DUMMY_LISTENER;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean stealTouchEvent = mInterceptTouchEventListener.onInterceptTouchEvent(this, ev, mDisallowIntercept);
return stealTouchEvent && !mDisallowIntercept || super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean handled = mInterceptTouchEventListener.onTouchEvent(this, event);
return handled || super.onTouchEvent(event);
}
}
Этот класс предоставляет setInterceptTouchEventListener()
для установки пользовательского перехватчика.
Когда требуется запретить перехват события касания, который он обманывает, он передает это в родительское представление, но продолжает перехватывать их.
Однако он больше не позволяет слушателю перехватывать события, поэтому, если слушатель возвращает true при событии перехвата касания, которое будет проигнорировано.
Таким образом, вы можете прозрачно получать каждое сенсорное событие, которое проходит через вашу ViewGroup, не нарушая поведение дочерних представлений.