Android Studio

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

정글(Jungle) 2020. 5. 3. 14:13
반응형

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

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

효과와 같은 것입니다. 

이 예제는 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);
        }
    }
}

 

 

 

반응형