Android

[Android] ViewPager2 - Runnable 객체로 자동으로 이미지 slide 하기

도우 2024. 3. 17. 16:03
반응형

탑툰을 클론코딩 하는 도중 이미지가 자동으로 slide 되는 UI를 구현해야 했다.

ViewPager2를 이용해서 구현해보도록 합시다

 

1. ViewPager2 선언

MainActivity에 HomeFragment가 존재하고, HomeFragment안에 ViewPager2를 다음과 같이 작성했습니다.

// fragment_home.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/slideViewPager"
        android:layout_width="match_parent"
        android:layout_height="220dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />



</androidx.constraintlayout.widget.ConstraintLayout>

 

2. ImageView가 포함된 페이지 레이아웃 만들기

ViewPager2의 각 페이지에 사용될 ImageView를 포함하는 레이아웃 XML 파일을 만들어야 합니다.
저는 사진만 들어가므로 ImageView 하나만 작성했습니다.

즉, Fragment에 뷰들을 관리하기 위해 ViewPager2를 작성했고, 뷰를 띄워줄 레이아웃을 지금 작성합니다.

// slide_image_row.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/slideImageRow"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop" />

</FrameLayout>

 

3. SlideImageAdapter 구현

ViewPager2는 내부적으로 RecycleView의 구현을 사용하기에 RecyclerView를 구현할 때와 유사하게 어댑터를 구현해야 합니다.  ViewHolder 패턴을 사용하기에 뷰를 재사용하고, 각 페이지에 해당하는 ImageView를 보관하고 관리합니다.

// SlideImageAdapter.java

public class SlideImageAdapter extends RecyclerView.Adapter<SlideImageAdapter.SlideImageViewHolder> {

    private Context context;
    private int[] images = new int[]{R.drawable.slide_add_1, R.drawable.slide_add_2, R.drawable.slide_add_3, R.drawable.slide_add_4, R.drawable.slide_add_5,
            R.drawable.slide_add_6, R.drawable.slide_add_7};
            // 이미지 파일 로컬에서 drawable에 저장함

    SlideImageAdapter(Context context) {
        this.context = context;
    }

    @NonNull
    @Override
    public SlideImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        SlideImageRowBinding binding = SlideImageRowBinding.inflate(LayoutInflater.from(context),parent,false);
        return new SlideImageViewHolder(binding);
    } 

    @Override
    public void onBindViewHolder(@NonNull SlideImageViewHolder holder, int position) {
        holder.binding.slideImageRow.setImageResource(images[position]);
    } // 각 페이지에 대한 데이터를 뷰에 바인딩할 때 호출함

    @Override
    public int getItemCount() {
        return images.length;
    }

    static class SlideImageViewHolder extends RecyclerView.ViewHolder {
        SlideImageRowBinding binding;

        SlideImageViewHolder(SlideImageRowBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}

 

 

3. 자동 슬라이딩 구현

Runnable 객체는 자바의 멀티스레딩 기능 중 하나로, 별도의 스레드에서 실행할 코드 블록을 정의합니다.

// HomeFragment.java

public class HomeFragment extends Fragment {
    private ViewPager2 slideViewPager;
    private int currentItem = 0;
    private FragmentHomeBinding binding;
    private Handler sliderHandler = new Handler();
    // Handler는 메시지나 Runnable 객체를 특정 시간 이후에 실행하도록 스케줄링함

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        binding = FragmentHomeBinding.inflate(inflater, container, false);

        slideViewPager = binding.slideViewPager;
        slideViewPager.setAdapter(new SlideImageAdapter(getContext()));

        // 자동 슬라이딩 구현
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if (currentItem >= slideViewPager.getAdapter().getItemCount()) {
                    currentItem = 0;
                }
                slideViewPager.setCurrentItem(currentItem++, true);
                // 전환할 페이지 인덱스와 애니메이션을 적용할지 여부(true)
                sliderHandler.postDelayed(this, 3000); 
                // 3초 후 다음 이미지로 전환, 재귀적 호출
            }
        };
        sliderHandler.postDelayed(runnable, 3000);

        return binding.getRoot();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        sliderHandler.removeCallbacksAndMessages(null); // 리소스 정리
        binding = null; // 메모리 누수 방지
    }
}

 

 

결과

기능적인 부분에서는 이상이 없지만, 애니메이션 속도가 가끔 너무 빠르게 지나가는 경우가 있다.
또한 사용자가 직접 스와이프 하는 와중에도 이미지가 바뀌기도 한다.

다음에는 Runnable과 Handler, 부드럽게 애니메이션을 적용하는 방법을 공부해 포스팅 해보도록 하겠습니다.

 

 

결과물

 

다음은 ViewPager2 좌측 하단에 Indicator를 만들어보도록 하겠습니다.

https://ehdnsdlek.tistory.com/32

 

[Android] ViewPager2에 custom indicator 연결하기

https://ehdnsdlek.tistory.com/31 저번 게시글에는 ViewPager2를 이용해서 자동으로 Slide 되게끔 만들어 보았습니다. 거기에 추가로 좌측 하단에 Indicator를 만들어 보겠습니다 1. customView를 만들기 위해 클래

ehdnsdlek.tistory.com

 

반응형