2016-03-03 11 views
3

Я использую RecyclerView с данными из SortedList с использованием SortedListAdapterCallback. Я хочу отключить анимацию для событий onChange, но сохраните их для onInserted/onRemoved/onMoved. Я попытался позвонить setSupportsChangeAnimations(false) на DefaultItemAnimator, используемом RecyclerView, но анимация все же появляется. Если я звоню setItemAnimator(null)все анимации успешно удаляются, как ожидалось.Отключить анимацию анимации на ItemAnimator для RecyclerView

Я попытался, глядя на реализации, и кажется, если supportsChangeAnimations является true, то RecyclerView будет анимировать событие изменения, сохраняя старую viewHolder и Затенение его к новому viewHolder. Я не хочу этого. Если supportsChangeAnimations - false, старый и новый viewHolders, однако, будут тем же самым объектом, и вместо этого будет анимация onMoved с 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 «s, показывает, что ни 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, когда нет анимации для запуска, но, увы, это обеспечивает желаемое поведение.

Подождите, но надеюсь, что это поможет!

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

хорошо, это может сработать, однако вопрос был связан строго отключить только OnChange и сохраняя другие анимации – cjurjiu

Смежные вопросы