2014-09-22 109 views
69

我在我的應用中實現了SwipeRefreshLayoutViewPager,但是存在很大的麻煩:每當我要向左/向右滑動以在頁面之間切換時,滾動過於敏感。輕掃一下也會觸發SwipeRefreshLayout刷新。SwipeRefreshLayout + ViewPager,僅限水平滾動?

我想設置水平滑動開始時的限制,然後強制水平,直到刷卡結束。換句話說,我想在手指水平移動時取消垂直翻轉。

這個問題只發生在ViewPager,如果我向下滑動,並且SwipeRefreshLayout刷新功能被觸發(條形圖顯示),然後我水平移動手指,它仍然只允許垂直滑動。

我試圖延長ViewPager類,但它不工作:

public class CustomViewPager extends ViewPager { 

    public CustomViewPager(Context ctx, AttributeSet attrs) { 
     super(ctx, attrs); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     boolean in = super.onInterceptTouchEvent(ev); 
     if (in) { 
      getParent().requestDisallowInterceptTouchEvent(true); 
      this.requestDisallowInterceptTouchEvent(true); 
     } 
     return false; 
    } 

} 

佈局的xml:

<android.support.v4.widget.SwipeRefreshLayout 
    android:id="@+id/viewTopic" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 
    <com.myapp.listloader.foundation.CustomViewPager 
     android:id="@+id/topicViewPager" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"/> 
</android.support.v4.widget.SwipeRefreshLayout> 

任何幫助,將不勝感激,謝謝

+0

如果viewpager中的某個片段具有'SwipeRefreshLayout',那麼相同的場景是否可以工作? – Zapnologica 2015-05-24 10:14:10

+0

https://androidbeasts.wordpress.com/2015/08/11/tabs-with-swipe-views/#more-79 – Aakash 2015-08-11 23:18:32

回答

25

解決得很乾脆不延長東西就像一個魅力

+0

好的,但請記住,您可能會在'ViewPager'中使用_any_可滾動的'View'相同的問題,因爲'SwipeRefreshLayout'只允許垂直滾動它的頂級子元素(並且在API下方只有當它恰好是一個ListView時才比ICS好)。 – corsair992 2014-09-23 12:12:56

+0

@ corsair992less謝謝你的提示 – user3896501 2014-09-23 16:31:57

+0

@ corsair992面臨的問題。我在'SwipeRefrestLayout'裏面有'ViewPager',ViewPager有'Listview'! 'SwipeRefreshLayout'讓我向下滾動,但向上滾動會觸發刷新進度。任何建議? – 2015-08-05 08:15:32

7

出於某種原因,只有他們才能知道,支持庫開發團隊認爲適合強制攔截所有垂直拖動動作fr即使孩子明確要求事件的所有權,也不例外。他們唯一檢查的是它的主子的垂直滾動狀態爲零(如果它的子是可垂直滾動的)。 requestDisallowInterceptTouchEvent()方法已被空體覆蓋,而(不是)照亮評論「不」。

解決此問題的最簡單方法是將該類從支持庫複製到項目中,並刪除方法覆蓋。 ViewGroup的實現使用內部狀態來處理onInterceptTouchEvent(),因此您不能簡單地重寫該方法並重復該方法。如果你真的想要覆蓋的支持庫實現,那麼你將不得不在requestDisallowInterceptTouchEvent()的調用中設置一個自定義標誌,並根據這個覆蓋onInterceptTouchEvent()onTouchEvent()(或可能hack canChildScrollUp())的行爲。

+0

男人,這很粗糙。我真的希望他們不會那樣做。我有一個列表,我想啓用拉刷新和刷新行項目的能力。他們創建SwipeRefreshLayout的方式幾乎是不可能的,沒有一些瘋狂的工作。 – 2015-06-01 20:49:48

9

我基於這一關前面的回答卻發現這個工作好一點

mPager.setOnTouchListener(new View.OnTouchListener() { 
    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     mLayout.setEnabled(false); 
     switch (event.getAction()) { 
      case MotionEvent.ACTION_UP: 
       mLayout.setEnabled(true); 
       break; 
     } 
     return false; 
    } 
}); 

工作。動作以ACTION_MOVE事件開始,以我的經驗結束於ACTION_UP或ACTION_CANCEL。

mViewPager.setOnTouchListener(new View.OnTouchListener() { 
    @Override 
    public boolean onTouch(View v, MotionEvent event) { 

     switch (event.getAction()) { 
      case MotionEvent.ACTION_MOVE: 
       mSwipeRefreshLayout.setEnabled(false); 
       break; 
      case MotionEvent.ACTION_UP: 
      case MotionEvent.ACTION_CANCEL: 
       mSwipeRefreshLayout.setEnabled(true); 
       break; 
     } 
     return false; 
    } 
}); 
111

我不知道如果你仍然有這個問題,但谷歌I/O應用iosched正是如此解決了這個問題:

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 
     @Override 
     public void onPageScrolled(int position, float v, int i1) { 
     } 

     @Override 
     public void onPageSelected(int position) { 
     } 

     @Override 
     public void onPageScrollStateChanged(int state) { 
      enableDisableSwipeRefresh(state == ViewPager.SCROLL_STATE_IDLE); 
     } 
    }); 


private void enableDisableSwipeRefresh(boolean enable) { 
    if (swipeContainer != null) { 
      swipeContainer.setEnabled(enable); 
    } 
} 

我已經使用了相同的和工作得很好。

編輯:使用addOnPageChangeListener()而不是setOnPageChangeListener()。

+3

這是最好的答案,因爲它考慮了ViewPager的狀態。它並不能阻止ViewPager產生的向下拖拽,這清楚地表明瞭刷新的意圖。 – Andy 2015-08-10 08:14:33

+4

最好的答案,但它可能是很好的發佈代碼enableDisableSwipeRefresh(是的,這是顯而易見的功能名稱..但要確保我不得不穀歌它...) – 2015-12-29 02:54:46

+1

應該是接受的答案。 – Michael 2016-01-18 16:42:33

12

我遇到了您的問題。自定義SwipeRefreshLayout可以解決問題。

public class CustomSwipeToRefresh extends SwipeRefreshLayout { 

private int mTouchSlop; 
private float mPrevX; 

public CustomSwipeToRefresh(Context context, AttributeSet attrs) { 
    super(context, attrs); 

    mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 
} 

@Override 
public boolean onInterceptTouchEvent(MotionEvent event) { 

    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      mPrevX = MotionEvent.obtain(event).getX(); 
      break; 

     case MotionEvent.ACTION_MOVE: 
      final float eventX = event.getX(); 
      float xDiff = Math.abs(eventX - mPrevX); 

      if (xDiff > mTouchSlop) { 
       return false; 
      } 
    } 

    return super.onInterceptTouchEvent(event); 
} 

見裁判:link

+0

這是最好的解決方案,在檢測中包含斜率。 – nafsaka 2015-11-04 11:04:18

+1

最佳解決方案。 +1 – 2016-06-28 11:54:06

1

有一個問題nhasan的解決方案:

如果觸發對SwipeRefreshLayoutsetEnabled(false)呼叫在OnPageChangeListener水平刷卡時會發生SwipeRefreshLayout有已經認識到Pull-to-Reload,但尚未調用通知回調,動畫消失,但SwipeRefreshLayout的內部狀態永遠保持「刷新」狀態,因爲沒有通知回調被調用,設置狀態。從用戶角度來看,這意味着由於所有拉動手勢都無法識別,所以「拉動重新加載」不再有效。

這裏的問題是disable(false)調用刪除了微調器的動畫,並且通知回調從該微調器的內部AnimationListener的onAnimationEnd方法中調用,該方法的設置無序。

它承認我們的測試人員用最快的手指挑起這種情況,但它也可能在現實場景中偶爾發生。

來解決這方面的一個解決方案是重寫onInterceptTouchEvent方法SwipeRefreshLayout如下:

public class MySwipeRefreshLayout extends SwipeRefreshLayout { 

    private boolean paused; 

    public MySwipeRefreshLayout(Context context) { 
     super(context); 
     setColorScheme(); 
    } 

    public MySwipeRefreshLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     setColorScheme(); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     if (paused) { 
      return false; 
     } else { 
      return super.onInterceptTouchEvent(ev); 
     } 
    } 

    public void setPaused(boolean paused) { 
     this.paused = paused; 
    } 
} 

使用MySwipeRefreshLayout在你的佈局 - 文件並更改代碼mhasan的解決

... 

@Override 
public void onPageScrollStateChanged(int state) { 
    swipeRefreshLayout.setPaused(state != ViewPager.SCROLL_STATE_IDLE); 
} 

... 
+0

我也有和你一樣的問題。只需用https://pastebin.com/XmfNsDKQ修改nhasan的解決方案注意刷新刷新佈局在刷新時不會產生問題,所以這就是檢查的原因。 – 2017-07-07 05:50:27