RecyclerView 항목이 나타날 때 애니메이션하는 방법


237

RecyclerView 항목이 나타날 때 어떻게 애니메이션을 적용 할 수 있습니까?

기본 아이템 애니메이터는 리사이클 러 데이터가 설정된 후 데이터가 추가되거나 제거 될 때만 애니메이션을 만듭니다. 저는 새로운 응용 프로그램을 개발 중이며 시작할 곳이 없습니다.

이것을 달성하는 방법에 대한 아이디어가 있습니까?

답변:


42

XML만으로 간단하게 제작

요점 링크 방문

res / anim / 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%" />

res / anim / item_animation_fall_down.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500">

    <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"
        />

</set>

레이아웃 및 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" />

1
@ArnoldBrown 애니메이션 파일을 변경합니다. 참조 : stackoverflow.com/questions/5151591/...
iamnaran

이것이 가장 실용적인 답변입니다.
Oliver Metz

목록을 열 때마다이 작업을 수행하는 방법 (처음으로 만 수행)
Hiwa Jalal

7
recyclerView.scheduleLayoutAnimation()데이터 세트가 변경된 후 호출해야합니다 . 그렇지 않으면 애니메이션이 작동하지 않습니다.
zeleven

품목을 재활용하고 다시 볼 때 이것이 효과가 있습니까? 이 솔루션을 시도했으며 레이아웃을 처음 볼 때 초기 애니메이션에 효과적입니다. 스크롤 후 항목을 다시 볼 때 애니메이션이 표시되지 않습니다.
Jason p

315

편집하다 :

ItemAnimator 설명서 에 따르면 :

이 클래스는 어댑터가 변경 될 때 항목에서 발생하는 애니메이션을 정의합니다.

따라서 항목을 하나씩 추가 RecyclerView하고 각 반복에서보기를 새로 고치지 않으면 ItemAnimator필요에 대한 해결책 이라고 생각하지 않습니다 .

RecyclerViewCustomAdapter를 사용하여 항목을 표시 할 때 애니메이션을 적용하는 방법은 다음과 같습니다 .

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's 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's 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의 저장소를 살펴보십시오 . 필요한 것을 찾을 수있을 것입니다. 그는 RecycleInView에 간단한 ItemAnimators를 제공합니다 (예 : SlideInItemAnimator 또는 SlideScaleItemAnimator).


1
나는 그것을 보았지만 그것이 나타난 후에 항목을 추가하고 제거하기위한 것입니다. 애니메이션이 나타나기 직전에 애니메이션을 시작해야합니다. 어쨌든 Mathieu 감사합니다.
PaulNunezM

1
내가 아는 한 CustomAdapter를 사용해야합니다.
MathieuMaree

20
RecyclerView에서 이러한 애니메이션으로 "고착 된"효과를 경험하고 해결했는지 궁금합니다. ListView에 비슷한 코드를 사용했는데 항목을 아무리 빠르게 스크롤해도 문제없이 애니메이션이 적용되었지만 RecyclerView를 사용하면 빠르게 스크롤하면 일부 항목이 때로는 다른 항목 위에 화면에 고정되어 완전히 숨겨지지 않습니다. -마치기 전에 애니메이션이 멈추는 것과 같습니다. 실제로 필드를 채우는 코드 부분을 주석 처리하려고 시도했습니다 (onBindViewHolder 메소드의 실행 속도를 높이려고 시도 중). 나는 animat에 대한 코드 만 남았습니다
Tomislav

4
@MathieuMaree이 놀라운 애니메이션에 감사드립니다. 느린 스크롤에는 좋지만 빠른 스크롤 리사이클 러보기 항목이 겹 쳤을 때이 문제가 발견 되었습니까?
Giru Bhai

40
@GiruBhai 가 뷰를 재정의 onViewDetachedFromWindow하고 호출 clearAnimation합니다. 문제는 RecyclerView가 뷰를 재사용하려고 할 때 애니메이션이 실행되고 있다는 것입니다.
Xample

62

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 밀리 초 동안 애니메이션 만 허용).


1
나는 단지 아래로 스크롤에 애니메이션 작업을 확인하는 귀하의 답변에 대한 작은 수정을 한 내 대답을
바시르 AL-MOMANI을

1
위아래로 빠르게 스크롤 할 때 레이아웃 (덮어 쓰기 된 목록 항목, 일부 텍스트 색상이 잘못됨)을
망칠 수 있습니다.

이것은 Recyclerview 항목에 애니메이션을 적용하는 올바른 방법이나 권장되지 않습니다. ItemAnimator 클래스를 사용해야합니다
Eco4ndly

25

애니메이션을 한 번만 실행하도록 pbm의 답변 에서 애니메이션을 거의 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's 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);            
}

1
lastPosition이란 무엇입니까? arrayList.size ()-1
Sumit Shukla

1
lastPositionITS의 값을 그 시작되도록 렌더링 조회수 나타내고 -1, 새로운 뷰 우리가 애니메이션을 시작 위치 증가 렌더링되는 모든 시간
바시르 AL-MOMANI

15

다음 과 같은 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


이것은 recyclerview가 처음로드 될 때 나에게 효과적이지만 새 항목을 추가 할 때는 그렇지 않았습니다. (나는 그것이 매우 좋은 일이었다고 생각하지만)
C. Skjerdal

8

시작하기 좋은 곳은 https://github.com/wasabeef/recyclerview-animators/blob/master/animators/src/main/java/jp/wasabeef/recyclerview/adapters/AnimationAdapter.java입니다.

당신은 전체 라이브러리가 필요하지 않습니다, 그 클래스는 충분합니다. 그런 다음 애니메이터를 제공하는 Adapter 클래스를 구현하면 다음과 같습니다.

@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);
}

스크롤 할 때 맨 아래부터 항목이 표시되고 빠른 스크롤 문제를 피할 수 있습니다.


3

재 순환기보기에서 항목이 어댑터에 바인드 될 때 항목을 애니메이션하면 재 순환기보기의 항목이 다른 속도로 애니메이션 될 수 있으므로 최상의 아이디어가 아닐 수 있습니다. 내 경우에는 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 단계는 동일하게 유지됩니다.

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에 애니메이션이 적용되어 화면 하단에서 날아갑니다.


당신은 전체 recyclerview 애니메이션에 대해 이야기합니다
Longerian

예-저는 전체 Recyclerview를 애니메이션하는 것이 각 항목보다 더 나은 아이디어라고 생각하는 이유에 대한 첫 번째 단락을 읽으십시오. 각 항목에 애니메이션을 적용 할 수는 있지만 좋지 않습니다.
Simon

무엇입니까 latestPostRecyclerview?
안토니오

1
아이템 뷰에 애니메이션을 적용하는 것이 그렇게 좋은 생각이 아닌 이유를 언급 한 대답의 첫 번째 단락을 읽었습니까? 또한 수락 된 솔루션을 사용해 보라고 제안한 다음 문제를 깨닫고 돌아와서이 솔루션을 사용해보십시오.
Simon

3

recyclerview 어댑터 에이 메소드를 작성하십시오.

private void setZoomInAnimation(View view) {
        Animation zoomIn = AnimationUtils.loadAnimation(context, R.anim.zoomin);// animation file 
        view.startAnimation(zoomIn);
    }

마지막으로 onBindViewHolder에이 코드 줄을 추가하십시오.

setZoomInAnimation(holder.itemView);


2

2019 년에는 모든 아이템 애니메이션을 ItemAnimator에 넣는 것이 좋습니다.

리사이클 러 뷰에서 애니메이터를 선언하는 것으로 시작하겠습니다.

with(view.recycler_view) {
adapter = Adapter()
itemAnimator = CustomAnimator()
}

그런 다음 사용자 정의 애니메이터를 선언하십시오.

class CustomAnimator() : DefaultItemAnimator() {

     override fun animateAppearance(
       holder: RecyclerView.ViewHolder,
       preInfo: ItemHolderInfo?,
       postInfo: ItemHolderInfo): Boolean{} // declare  what happens when a item appears on the recycler view

     override fun animatePersistence(
       holder: RecyclerView.ViewHolder,
       preInfo: ItemHolderInfo,
       postInfo: ItemHolderInfo): Boolean {} // declare animation for items that persist in a recycler view even when the items change

}

위의 것들과 유사하게, 사라짐 animateDisappearance, 추가 animateAdd, 변화 animateChange및 이동을 위한 것이 있습니다 animateMove.

한 가지 중요한 점은 올바른 애니메이션 디스패처를 호출하는 것입니다.


이 재정의 기능을 사용하여 사용자 지정 모양 애니메이션의 예를 제공 할 수 있습니까? 예제를 찾을 수 없으며 함수에서 애니메이션을 지정 해야하는지 확실하지 않습니다.
9

1
gist.github.com/tadfisher/120d03f8380bfa8a16bf 빠른 검색에서이 온라인을 찾았습니다. 이렇게하면 과부하 작동 방식에 대한 아이디어를 얻을 수 있습니다
Dinesh

0

아래처럼 어댑터를 확장하십시오.

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;
        }
    }

}

0

다음과 같이 사용하는 것이 좋습니다. (RecyclerView 어댑터 에서 한 가지 방법 만 재정의)

override fun onViewAttachedToWindow(holder: ViewHolder) {
    super.onViewAttachedToWindow(holder)

    setBindAnimation(holder)
}

RV에 모든 첨부 애니메이션이 필요한 경우.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.