본문 바로가기

Android Studio

리사이클러뷰 애니메이션 - RecyclerView Animation

반응형

리스트 뷰를 아래 위로 움직여 쌓이는 효과를 구현해 보려 합니다.

예로 배달의 민족 어플에 보면 가계 목록들 움직여 보면 아래위로 조금씩 떨어져 있다 차곡차곡 쌓이는

효과와 같은 것입니다. 

이 예제는 RecyclerView Adapter를 구현하실 수 있으며 이해하고 있다는 전제하에서 진행하겠습니다.

 

우선 안드로이드 스튜디오의 res 폴더에 anim 폴더를 만들어 줍니다.

* res 폴더에 마우스 오른쪽 클릭 후 New > Android Resource Directory 선택 > Resourcetype에서 anim 선택 후 OK

 

anim 폴더에서 마우스 오른쪽 클릭 후 New > Animation Resource File 선택 > File name을 down으로 지정 후  Ok

 

down.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromYDelta="15%"
        android:toYDelta="0%"
        android:duration="300" />
</set>

위와 같은 방법으로

up.xml 

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromYDelta="-15%"
        android:toYDelta="0%"
        android:duration="300" />
</set>

Y축 첫 시작 위치를 현재 위치에서 15% 떨어져 시작하며 0.3초 동안 원래 위치 0%로 돌아오는 애니메이션입니다.

fromYDelta 값을 수정하시면 간격을 조절하실 수 있습니다.

 

애니메이션을 위해서 Adapter를 호출하는 코드에서 Adapter에 Context를 전달해야 합니다.

 

예로)

private Context context;

 

public TestAdapter(Context context) {
     this.context = context;
}

 

애니메이션을 구현하기 위해 Adapter에서 자료를 표시하는 TextView 뿐 아니라 모든 뷰를 감싸고 있는 부모 Layout를 

가져와야 합니다. 

public static class VH extends RecyclerView.ViewHolder {
	LinearLayout bodyView;
    
    public VH(@NonNull View itemView) {
        super(itemView);
		bodyView = itemView.findViewById(R.id.body_view);
    }
}

LinearLayout bodyView;

 

Adapter의 Item_View 의 첫 시작 부모 뷰가 가령 LinearLayout이고 findViewById를 받아올 이름을 bodyView라고 하겠습니다.

이렇게 가져온 bodyView에 애니메이션을 적용하게 됩니다.

 

private int positionCheck;

private boolean isStartViewCheck = true;

 

positionCheck는 현재 화면에서 아래위 이동을 체크하기 위한 변수입니다.

첫 시작 화면인지 판단하기 위해 isStartViewCheck를 주었습니다.

 

이제 실제 애니메이션을 구현해 보면..

Adapter의 onBindViewHolder 안에 구현해 주시면 됩니다.

@Override
public void onBindViewHolder(@NonNull VH holder, int position) {

if (isStartViewCheck) {
            if (position > 6) isStartViewCheck = false;
        } else {
            if (position > positionCheck) {
                holder.bodyView.setAnimation(AnimationUtils.loadAnimation(context, R.anim.down));
            } else {
                holder.bodyView.setAnimation(AnimationUtils.loadAnimation(context, R.anim.up));
            }
        }
 
 
 // 어뎁터 데이터 화면 표시 구간    
 holder.textview.setText("데이터 표시");      
 
 
 // 현재 위치값을 positionCheck에 저장 - onBindViewHolder 마지막 부분에 구현
 positionCheck = position;
 }

 

리사이클러뷰가 실행된 후 첫 데이터를 화면에 뿌리면 isStartViewCheck로 지정된 수량의 데이터가 화면에 표시되기 까진 애니메이션을 못하게 막아 줍니다. 

** 처음부터 바로 애니메이션을 보고 싶으시면 이 부분은 빼도 되지만 첫 화면이 열릴때는 없는 게 보기 좋더군요.

 

화면에 움직임이 있을 경우 positionCheck에 저장된 위치 값을 이용해 현재 화면의 데이터 표시가 위로 움직이는지 또는 아래로 움직이는지를 체크 후 움직이는 방향에 맞게 애니메이션을 표시해 줍니다.

부모 뷰가 되는 bodyView에 setAnimation을 주었으며 애니메이션 xml을 다른 것으로 변경해 주시면 여러 효과를 이용하실 수 있습니다.

 

이상 간단하지만 실용적인 Adapter 애니메이션을 구현해 보았습니다. ~~

 

전체 코드 (Adapter 애니메이션 구현을 위한 코드부분만 들어가 있습니다.)

public class TestAdapter extends RecyclerView.Adapter<TestAdapter.VH> {
    private Context context;
    private int positionCheck = 0;

    private boolean isStartViewCheck = true;

    public TestAdapter(Context context) {
        this.context = context;
    }

    @Override
    public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_view, parent, false);
        final VH viewHolder = new VH(view);
        
        // ...

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull VH holder, int position) {

        if (isStartViewCheck) {
            if (position > 6) isStartViewCheck = false;
        } else {
            if (position > positionCheck) {
                holder.bodyView.setAnimation(AnimationUtils.loadAnimation(context, R.anim.down));
            } else {
                holder.bodyView.setAnimation(AnimationUtils.loadAnimation(context, R.anim.up));
            }
        }

        // 사용자 데이터 처리 

        positionCheck = position;
    }


    public static class VH extends RecyclerView.ViewHolder {
        LinearLayout bodyView;

        public VH(@NonNull View view) {
            super(view);
            
            bodyView = view.findViewById(R.id.body_view);
        }
    }
}

 

 

 

반응형