2016-04-11 9 views
2

Ich habe ein ViewPager die Swipe berührt aktiviert oder deaktiviert werden können:deaktivieren Swipe auf einige Fragmente in ViewPager

public class ConfigurablePager extends ViewPager { 

    private final AtomicBoolean touchesAllowed = new AtomicBoolean(); 

    ... 

    private boolean touchesAllowed() { 
     return touchesAllowed.get(); 
    } 

    public void enableTouches() { 
     touchesAllowed.set(true); 
    } 

    public void disableTouches() { 
     touchesAllowed.set(false); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent ev) { 
     return touchesAllowed() && super.onTouchEvent(ev); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     return touchesAllowed() && super.onInterceptTouchEvent(ev); 
    } 
} 

Einige Fragmente geklaut werden kann, aber andere nicht. Pager-Adapter erkennt das Wischverhalten für jedes Fragment.

@Override 
public void onPageSelected(int position) { 
    if (adapter.isTouchesAllowed(position)) { 
     views.pager.enableTouches(); 
    } else { 
     views.pager.disableTouches(); 
    } 
} 

Das Problem
Manchmal, wenn ich Fragmente sehr schnell, und klicken Sie auf den Reiter für andere Fragment Swipe gleichzeitig viewpager IllegalArgumentException werfen kann: Dieses Verhalten kann in ViewPager.OnPageChangeListener geändert werden

FATAL AUSNAHME:
main java.lang.IllegalArgumentException: pointerIndex außerhalb des Bereichs
bei android.view.Moti onEvent.nativeGetAxisValue (native Methode)
bei android.view.MotionEvent.getX (MotionEvent.java:1979)
bei android.support.v4.view.MotionEventCompatEclair.getX (MotionEventCompatEclair.java:32)
bei android. support.v4.view.MotionEventCompat $ EclairMotionEventVersionImpl.getX (MotionEventCompat.java:110)
bei android.support.v4.view.MotionEventCompat.getX (MotionEventCompat.java:462)
bei android.support.v4.view. ViewPager.onTouchEvent (ViewPager.java:2080)
bei com.test.debugpager.ConfigurablePager.onTouchEvent (ConfigurablePager.java:39)
bei android.view.View.dispatchTouchEvent (Vi ew.java:7384)
bei android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2203)
bei android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:1938)
bei android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2231)
bei android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:1952)
bei android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2209)

Es ist happend weil ViewPager letzte pointerId speichern und inkonsistenten Zustand erhalten (einige t Autscheneignisse fallen um onInterceptTouchEvent) z. ACTION_MOVE mit falschen mActivePointerId von den letzten Berührungsereignis (siehe Quellen ViewPager.java)

Die Frage
Ist es posible Swipe auf einige Fragmente auf andere Weise zu deaktivieren, vielleicht ohne onInterceptTouchEvent überschrieben?

ViewPager Quellen (onTouchEvent):

case MotionEvent.ACTION_MOVE: 
    if (!mIsBeingDragged) { 
     final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); 
     final float x = MotionEventCompat.getX(ev, pointerIndex); 
     final float xDiff = Math.abs(x - mLastMotionX); 
     final float y = MotionEventCompat.getY(ev, pointerIndex); 
     final float yDiff = Math.abs(y - mLastMotionY); 
     if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); 
     if (xDiff > mTouchSlop && xDiff > yDiff) { 
      if (DEBUG) Log.v(TAG, "Starting drag!"); 
      mIsBeingDragged = true; 
      requestParentDisallowInterceptTouchEvent(true); 
      mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop : 
      mInitialMotionX - mTouchSlop; 
      mLastMotionY = y; 
      setScrollState(SCROLL_STATE_DRAGGING); 
      setScrollingCacheEnabled(true); 

      // Disallow Parent Intercept, just in case 
      ViewParent parent = getParent(); 
      if (parent != null) { 
       parent.requestDisallowInterceptTouchEvent(true); 
      } 
     } 
    } 

Antwort

0

Gelöst

ich aufmerksam gelesen habe android guide über Geste in einem ViewGroup erkennen und analysiert ViewPageronTouchEvent Quellen.Hier erkenne ich, dass ViewPager wischen nur für ACTION_MOVE Ereignis, so dass wir keine Touch-Callbacks nur für diese Aktion aufrufen sollten und wir sollten Basis ViewGrouponInterceptTouchEvent Ergebnis vor dem Aufruf der Basisklasse onTouchEvent.

Nach diesen Regeln änderte ich meinen ViewPager Code:

@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) { 
    if (touchesAllowed()) { 
     return super.onInterceptTouchEvent(ev); 
    } else { 
     if (MotionEventCompat.getActionMasked(ev) == MotionEvent.ACTION_MOVE) { 
      // ignore move action 
     } else { 
      if (super.onInterceptTouchEvent(ev)) { 
       super.onTouchEvent(ev); 
      } 
     } 
     return false; 
    } 
} 

@Override 
public boolean onTouchEvent(MotionEvent ev) { 
    if (touchesAllowed()) { 
     return super.onTouchEvent(ev); 
    } else { 
     return MotionEventCompat.getActionMasked(ev) != MotionEvent.ACTION_MOVE && super.onTouchEvent(ev); 
    } 
}