2016-04-11 5 views
2

У меня есть ViewPager, которые можно отключить или включить мазковые штрихи:Отключить салфетки на некоторых фрагментов в 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); 
    } 
} 

Некоторые фрагменты могут быть наотмашь, но другие не могут. Адаптер пейджера осознает поведение салфеток для каждого фрагмента. Такое поведение может быть изменено в ViewPager.OnPageChangeListener:

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

Проблема
Иногда, когда я красть фрагменты очень быстро и нажмите на вкладку для другого фрагмента одновременно ViewPager может бросить IllegalArgumentException:

FATAL ИСКЛЮЧЕНИЕ:
main java.lang.IllegalArgumentException: pointerIndex вне допустимого диапазона
на android.view.Moti onEvent.nativeGetAxisValue (Родной метод)
в android.view.MotionEvent.getX (MotionEvent.java:1979)
в android.support.v4.view.MotionEventCompatEclair.getX (MotionEventCompatEclair.java:32)
на андроид. support.v4.view.MotionEventCompat $ EclairMotionEventVersionImpl.getX (MotionEventCompat.java:110)
в android.support.v4.view.MotionEventCompat.getX (MotionEventCompat.java:462)
в android.support.v4.view. ViewPager.onTouchEvent (ViewPager.java:2080)
at com.test.debugpager.ConfigurablePager.onTouchEvent (ConfigurablePager.java:39)
по android.view.View.dispatchTouchEvent (Vi ew.java:7384)
на android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2203)
в android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:1938)
в android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2231)
в android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:1952)
в android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2209)

Это сЛУЧИЛОСЬ потому что ViewPager сохранить последний pointerId и получить несогласованное состояние (некоторые t ouch события, упавшие на onInterceptTouchEvent), например. ACTION_MOVE с неправильным mActivePointerId от последнего касания события (см источников ViewPager.java)

Вопрос
ли отключить Возможный красть на некоторых фрагментах другого способа, может быть, не перекрывая onInterceptTouchEvent?

источники ViewPager (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); 
      } 
     } 
    } 

ответ

0

решаемых

Я прочитал внимательно android guide о жестом признании в ViewGroup и проанализированы ViewPageronTouchEvent источников.Здесь я признаю, что ViewPager делают салфетки только для события ACTION_MOVE, поэтому мы не должны вызывать touch callbacks только для этого действия, и мы должны подчиняться основанию ViewGrouponInterceptTouchEvent результат перед вызовом базового класса onTouchEvent.

Согласно этим правилам я изменил свой ViewPager код:

@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); 
    } 
} 
Смежные вопросы