2016-03-03 78 views
3

我使用的是RecyclerView,使用SortedListAdapterCallback來自SortedList的數據。我想要禁用onChange事件的動畫,但將其保留爲onInserted/onRemoved/onMoved。我試過在RecyclerView使用的DefaultItemAnimator上嘗試撥打setSupportsChangeAnimations(false),但動畫仍然出現。如果我撥打電話setItemAnimator(null)所有動畫按預期成功刪除。在ItemAnimator上爲RecyclerView禁用onChange動畫

我試圖尋找的實現,它好像如果supportsChangeAnimationstrue,該RecyclerView將保留舊viewHolder並淡入淡出到新viewHolder動畫更改事件。我不想那樣。如果supportsChangeAnimationsfalse,則舊的和新的viewHolders將是相同的對象,並且將會改爲從x到x的動畫(即,沒有實際的移動)。但是這意味着該物品會產生惱人的反彈效果。我也不想要那個,我根本不需要動畫。 :(

從DefaultItemAnimator.java:

@Override 
public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, 
     int fromX, int fromY, int toX, int toY) { 
    if (oldHolder == newHolder) { 
     // Don't know how to run change animations when the same view holder is re-used. 
     // run a move animation to handle position changes. 
     return animateMove(oldHolder, fromX, fromY, toX, toY); 
    } 
    ... 

有時,當我載入我的列表我取異步一些數據,並更新項目1-3倍,它看起來非常糟糕時,它反彈和閃爍每次。

我如何有效地完全禁用onChange動畫,而不訴諸寫一個完全自定義ItemAnimator

回答

3

通過閱讀代碼(我使用的是支持庫25.2.0):setSupportsChangeAnimations(<value>)是抽象類SimpleItemAnimator的一種方法,它也是DefaultItemAnimator的超類。在內部,它修改了mSupportsChangeAnimations的值。

DefaultItemAnimator的代碼中執行文本搜索,發現既沒有mSupportsChangeAnimations也沒有getSupportsChangeAnimations()被查詢 - >DefaultItemAnimator從字面上忽略了該標誌。

正確的解決方案是將DefaultItemAnimator以下方式擴展:

public class CustomItemAnimator extends DefaultItemAnimator { 
@Override 
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) { 
    if (getSupportsChangeAnimations()) { 
     return super.animateChange(oldHolder, newHolder, fromX, fromY, toX, toY); 
    } else { 
     if (oldHolder == newHolder) { 
      if (oldHolder != null) { 
       //if the two holders are equal, call dispatch change only once 
       dispatchChangeFinished(oldHolder, /*ignored*/true); 
      } 
     } else { 
      //else call dispatch change once for every non-null holder 
      if (oldHolder != null) { 
       dispatchChangeFinished(oldHolder, true); 
      } 
      if (newHolder != null) { 
       dispatchChangeFinished(newHolder, false); 
      } 
     } 
     //we don't need a call to requestPendingTransactions after this, return false. 
     return false; 
    } 
} 

見文檔animateChange(...)理解爲什麼它需要調用dispatchChangeFinished(...)當沒有動畫中運行。

當沒有動畫需要運行時,可能有更優雅的方式來編寫else分支,但是,這實現了所需的行爲。

Kind'of late,但希望這有助於!

1

上面的解決方案不適用於支持庫版本25.3.1,因爲我想禁用所有回收器視圖項目的動畫。我通過覆蓋SimpleItemAnimator解決了這個問題:

private class NoAnimationItemAnimator extends SimpleItemAnimator { 
    @Override 
    public boolean animateRemove(RecyclerView.ViewHolder holder) { 
     dispatchRemoveFinished(holder); 

     return false; 
    } 

    @Override 
    public boolean animateAdd(RecyclerView.ViewHolder holder) { 
     dispatchAddFinished(holder); 

     return false; 
    } 

    @Override 
    public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) { 
     dispatchMoveFinished(holder); 

     return false; 
    } 

    @Override 
    public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) { 
     dispatchChangeFinished(oldHolder, true); 
     dispatchChangeFinished(newHolder, false); 

     return false; 
    } 

    @Override 
    public void runPendingAnimations() { 
     // stub 
    } 

    @Override 
    public void endAnimation(RecyclerView.ViewHolder item) { 
     // stub 
    } 

    @Override 
    public void endAnimations() { 
     // stub 
    } 

    @Override 
    public boolean isRunning() { 
     return false; 
    } 
} 
+0

好吧,它可能會工作, – cjurjiu