Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>To prevent touches from that layout you have several options:</p> <p>1) set OnTouchListener, which would always return true.</p> <p>2) override dispatchTouchEvent(MotionEvent event) to always return true</p> <p><strong>UPD:</strong> Okey, normally you would have to set OnTouchListener, which would always return true, as I said previously to prevent other views from being called <code>onTouch</code>, but with ScrollView it's completely another story.</p> <p>First of all I will tell how <code>dispatchTouchEvent</code> works. It starts dispatching event from the root view to it's child views, so that means that <code>dispatchTouchEvent</code> of parent is called <em>BEFORE</em> <code>dispatchTouchEvent</code> of it's children. </p> <p>Then in <code>ViewGroup.dispatchTouchEvent()</code> there is a piece of code </p> <pre><code>final boolean disallowIntercept = (mGroupFlags &amp; FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore action in case it was changed } else { intercepted = false; } </code></pre> <p>which decides if this touch event should be intercepted, which means if <code>intercepted</code> flag is true, then this view would intercept all successive event. And in <code>ScrollView</code> <code>onInterceptTouchEvent</code> implemented to intercept actions if they are perfroming vertical scrolling.</p> <p>So my first idea was to set <code>FLAG_DISALLOW_INTERCEPT</code> to the parent of your custom view to disallow this opportunity of intercepting events, but this idea fails because of the next lines of code in <code>ViewGroup</code>:</p> <pre><code>if (actionMasked == MotionEvent.ACTION_DOWN) { // Throw away all previous state when starting a new touch gesture. // The framework may have dropped the up or cancel event for the previous gesture // due to an app switch, ANR, or some other state change. cancelAndClearTouchTargets(ev); resetTouchState(); } </code></pre> <p>So that means that after the <code>MotionEvent.ACTION_DOWN</code> all states are cleared (and so do <code>FLAG_DISALLOW_INTERCEPT</code> is also cleared).</p> <p>So the final solution is pretty simple</p> <pre><code>public class PreventingTouchEventView extends View { public PreventingTouchEventView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.RED); } @Override public boolean dispatchTouchEvent(MotionEvent event) { if (getParent() != null &amp;&amp; event.getAction() == MotionEvent.ACTION_DOWN) { getParent().requestDisallowInterceptTouchEvent(true); } return super.dispatchTouchEvent(event); } } </code></pre> <p>this would raise <code>FLAG_DISALLOW_INTERCEPT</code> right after first <code>MotionEvent.ACTION_DOWN</code>, which would dissallow further interception of future actions by parent. </p> <p>But note, that if your parent view doing some crazy stuff on <code>MotionEvent.ACTION_DOWN</code> and intercepting this event then you just can't do anything about it, because your parent's <code>dispatchTouchEvent</code> are called before your <code>dispatchTouchEvent</code>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload