Как оживить элементы RecyclerView, когда они появляются
Как я могу анимировать элементы RecyclerView, когда они появляются?
Аниматор элемента по умолчанию анимируется только тогда, когда данные добавляются или удаляются после того, как были установлены данные переработчика. Я занимаюсь разработкой новых приложений и понятия не имею, с чего начать.
Есть идеи как этого добиться?
Ответы
Ответ 1
Сделано просто только с XML
Посетите Gist Link
Рез/аним /layout_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/item_animation_fall_down"
android:animationOrder="normal"
android:delay="15%" />
Рез/аним /item_animation_fall_down.xml
<translate
android:fromYDelta="-20%"
android:toYDelta="0"
android:interpolator="@android:anim/decelerate_interpolator"
/>
<alpha
android:fromAlpha="0"
android:toAlpha="1"
android:interpolator="@android:anim/decelerate_interpolator"
/>
<scale
android:fromXScale="105%"
android:fromYScale="105%"
android:toXScale="100%"
android:toYScale="100%"
android:pivotX="50%"
android:pivotY="50%"
android:interpolator="@android:anim/decelerate_interpolator"
/>
Используйте в макетах и recylcerview, как:
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutAnimation="@anim/layout_animation"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
Ответ 2
EDIT:
В соответствии с документацией ItemAnimator:
Этот класс определяет анимации, которые происходят на элементах, поскольку изменения внесены в адаптер.
Поэтому, если вы не добавите свои элементы по одному в свой RecyclerView
и обновите представление на каждой итерации, я не думаю, что ItemAnimator
является решением вашей потребности.
Вот как вы можете анимировать элементы RecyclerView
, когда они появляются с помощью CustomAdapter:
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder>
{
private Context context;
// The items to display in your RecyclerView
private ArrayList<String> items;
// Allows to remember the last item shown on screen
private int lastPosition = -1;
public static class ViewHolder extends RecyclerView.ViewHolder
{
TextView text;
// You need to retrieve the container (ie the root ViewGroup from your custom_item_layout)
// It the view that will be animated
FrameLayout container;
public ViewHolder(View itemView)
{
super(itemView);
container = (FrameLayout) itemView.findViewById(R.id.item_layout_container);
text = (TextView) itemView.findViewById(R.id.item_layout_text);
}
}
public CustomAdapter(ArrayList<String> items, Context context)
{
this.items = items;
this.context = context;
}
@Override
public CustomAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_item_layout, parent, false);
return new ViewHolder(v);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position)
{
holder.text.setText(items.get(position));
// Here you apply the animation when the view is bound
setAnimation(holder.itemView, position);
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position)
{
// If the bound view wasn't previously displayed on screen, it animated
if (position > lastPosition)
{
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
}
И ваш custom_item_layout будет выглядеть так:
<FrameLayout
android:id="@+id/item_layout_container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/item_layout_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"/>
</FrameLayout>
Дополнительные сведения о CustomAdapters и RecyclerView
см. в этом обучении по официальной документации.
Проблемы с быстрой прокруткой
Использование этого метода может вызвать проблемы с быстрой прокруткой. Представление может быть повторно использовано во время анимации. Чтобы избежать этого, рекомендуется очистить анимацию при отсоединении.
@Override
public void onViewDetachedFromWindow(final RecyclerView.ViewHolder holder)
{
((CustomViewHolder)holder).clearAnimation();
}
В CustomViewHolder:
public void clearAnimation()
{
mRootLayout.clearAnimation();
}
Старый ответ:
Посмотрите Gabriele Mariotti repo, я уверен, что вы найдете то, что вам нужно. Он предоставляет простые ItemAnimators для RecyclerView, такие как SlideInItemAnimator или SlideScaleItemAnimator.
Ответ 3
Я анимировал появление элементов Recyclerview
, когда они впервые появляются, как показано в коде ниже. Возможно, это кому-нибудь пригодится.
private final static int FADE_DURATION = 1000; //FADE_DURATION in milliseconds
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.getTextView().setText("some text");
// Set the view to fade in
setFadeAnimation(holder.itemView);
}
private void setFadeAnimation(View view) {
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
anim.setDuration(FADE_DURATION);
view.startAnimation(anim);
}
Вы также можете заменить setFadeAnimation()
на следующую setScaleAnimation()
чтобы анимировать внешний вид элементов, масштабируя их из точки:
private void setScaleAnimation(View view) {
ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(FADE_DURATION);
view.startAnimation(anim);
}
Приведенный выше код имеет некоторые недостатки, поскольку при прокрутке элементы RecyclerView
всегда исчезают или масштабируются. Если вы хотите, вы можете добавить код, чтобы позволить анимации происходить при первом создании фрагмента или действия, содержащего RecyclerView
(например, получить системное время при создании и разрешить анимацию только в течение первых миллисекунд FADE_DURATION).
Ответ 4
Я создал анимацию из pbm answer с небольшим modification
, чтобы анонимность выполнялась только один раз
в другом слове Animation appear with you scroll down only
private int lastPosition = -1;
private void setAnimation(View viewToAnimate, int position) {
// If the bound view wasn't previously displayed on screen, it animated
if (position > lastPosition) {
ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(new Random().nextInt(501));//to make duration random number between [0,501)
viewToAnimate.startAnimation(anim);
lastPosition = position;
}
}
и в onBindViewHolder
вызовите функцию
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.getTextView().setText("some text");
// call Animation function
setAnimation(holder.itemView, position);
}
Ответ 5
Вы можете добавить android:layoutAnimation="@anim/rv_item_animation"
в RecyclerView
следующим образом:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutAnimation="@anim/layout_animation_fall_down"
/>
спасибо за отличную статью здесь: https://proandroiddev.com/enter-animation-using-recyclerview-and-layoutanimation-part-1-list-75a874a5d213
Ответ 6
Хорошее место для начала:
https://github.com/wasabeef/recyclerview-animators/blob/master/animators/src/main/java/jp/wasabeef/recyclerview/adapters/AnimationAdapter.java
Вам даже не нужна полная библиотека, этого класса достаточно.
Затем, если вы просто реализуете свой класс адаптера, предоставляя аниматор следующим образом:
@Override
protected Animator[] getAnimators(View view) {
return new Animator[]{
ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0)
};
}
@Override
public long getItemId(final int position) {
return getWrappedAdapter().getItemId(position);
}
вы увидите элементы, появляющиеся снизу, когда они прокручиваются, а также избегают проблемы с быстрым прокруткой.
Ответ 7
Анимация элементов в recyclerview, когда они привязаны к адаптеру, может быть не лучшей идеей, поскольку это может привести к оживлению элементов в recyclerview на разных скоростях. В моем случае предмет в конце recyclerview приближается к своей позиции быстрее, чем те, что наверху, поскольку те, что наверху, продолжают путешествовать, поэтому он выглядел неопрятным.
Исходный код, который я использовал для анимации каждого элемента в recyclerview, можно найти здесь:
http://frogermcs.github.io/Instagram-with-Material-Design-concept-is-getting-real/
Но я буду копировать и вставлять код в случае разрыва ссылки.
ШАГ 1: Установите это внутри метода onCreate, чтобы обеспечить, чтобы анимация запускалась только один раз:
if (savedInstanceState == null) {
pendingIntroAnimation = true;
}
ШАГ 2: Вам нужно будет поместить этот код в метод, в котором вы хотите запустить анимацию:
if (pendingIntroAnimation) {
pendingIntroAnimation = false;
startIntroAnimation();
}
В ссылке писатель анимирует значки на панели инструментов, поэтому он поместил ее внутри этого метода:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
inboxMenuItem = menu.findItem(R.id.action_inbox);
inboxMenuItem.setActionView(R.layout.menu_item_view);
if (pendingIntroAnimation) {
pendingIntroAnimation = false;
startIntroAnimation();
}
return true;
}
ШАГ 3: Теперь напишите логику для startIntroAnimation():
private static final int ANIM_DURATION_TOOLBAR = 300;
private void startIntroAnimation() {
btnCreate.setTranslationY(2 * getResources().getDimensionPixelOffset(R.dimen.btn_fab_size));
int actionbarSize = Utils.dpToPx(56);
toolbar.setTranslationY(-actionbarSize);
ivLogo.setTranslationY(-actionbarSize);
inboxMenuItem.getActionView().setTranslationY(-actionbarSize);
toolbar.animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(300);
ivLogo.animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(400);
inboxMenuItem.getActionView().animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(500)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
startContentAnimation();
}
})
.start();
}
Моя предпочтительная альтернатива:
Я предпочел бы анимировать весь recyclerview вместо элементов внутри recyclerview.
ШАГ 1 и 2 остаются теми же.
В STEP 3, как только ваш вызов API вернется с вашими данными, я начну анимацию.
private void startIntroAnimation() {
recyclerview.setTranslationY(latestPostRecyclerview.getHeight());
recyclerview.setAlpha(0f);
recyclerview.animate()
.translationY(0)
.setDuration(400)
.alpha(1f)
.setInterpolator(new AccelerateDecelerateInterpolator())
.start();
}
Это позволит анимировать весь ваш recyclerview, чтобы он летел в нижней части экрана.
Ответ 8
Создайте этот метод в своем адаптере recyclerview
private void setZoomInAnimation(View view) {
Animation zoomIn = AnimationUtils.loadAnimation(context, R.anim.zoomin);// animation file
view.startAnimation(zoomIn);
}
И, наконец, добавьте эту строку кода в onBindViewHolder
setZoomInAnimation(holder.itemView);
Ответ 9
Просто расширяет ваш адаптер, как показано ниже
public class RankingAdapter extends AnimatedRecyclerView<RankingAdapter.ViewHolder>
И добавьте супер метод к onBindViewHolder
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
super.onBindViewHolder(holder, position);
Это автоматизирует способ создания анимированного адаптера, такого как "Basheer AL-MOMANI"
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import java.util.Random;
/**
* Created by eliaszkubala on 24.02.2017.
*/
public class AnimatedRecyclerView<T extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<T> {
@Override
public T onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(T holder, int position) {
setAnimation(holder.itemView, position);
}
@Override
public int getItemCount() {
return 0;
}
protected int mLastPosition = -1;
protected void setAnimation(View viewToAnimate, int position) {
if (position > mLastPosition) {
ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(new Random().nextInt(501));//to make duration random number between [0,501)
viewToAnimate.startAnimation(anim);
mLastPosition = position;
}
}
}
Ответ 10
Добавьте эту строку в RecyclerView.xml
android:animateLayoutChanges="true"