티스토리 뷰

ViewPager2를 이용한 무한 Margin 페이지

Android ViewPager2를 이용해서 무한 Margin 페이지를 구현해보겠습니다.

 

가장 먼저 pager에 보여질 Item layout을 구성합니다.

그리고 각 아이템 간에 margin을 두어 위에 이미지 처럼 간격을 줍니다.

 

row_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_marginLeft="@dimen/pageMarginAndOffset"
    android:layout_marginRight="@dimen/pageMarginAndOffset"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/imgBanner"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorAccent"
        android:contentDescription="@string/app_name"/>

    <TextView
        android:id="@+id/tvName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:layout_centerInParent="true"
        android:textColor="@android:color/white"
        android:textSize="20sp"
        android:textStyle="bold"
        tools:text="Hello"/>

</RelativeLayout>

 

dimens.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="pageMargin">30dp</dimen>
    <dimen name="offset">30dp</dimen>
    <dimen name="pageMarginAndOffset">50dp</dimen>
</resources>

 

이제 ViewPager를 추가해보겠습니다.

추가하기 전에 라이브러리를 추가해야 합니다. build.gradle에 아래 내용을 추가 해주시기 바랍니다.

dependencies {
...
    implementation 'androidx.viewpager2:viewpager2:1.0.0'
}

 

clipChildren와 clipToPadding을 false로 적용합니다. clipChildren는 child view들이 영역안에서 보여지게 해주는 옵션으로 item간 margin을 적용하기 위해서는 해당 옵션을 false해야 합니다.

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager2"
        android:clipToPadding="false"
        android:clipChildren="false"
        android:layout_width="match_parent"
        android:layout_height="250dp" />

</LinearLayout>

 

요번에는 pager를 위한 adapter를 작성해보겠습니다.

ViewPager와 달라진 점이 ViewPager2에서는 RecyclerView를 사용할 수 있다는 점입니다.

 

제목에는 무제한이라고 표현했지만, 정확히 말하면 Integer Max(2147483647) 만큼 반복해서 보여지게하여 무제한처럼 보여지게 하는 방법입니다.

이를 위해서 getItemCount 값을 Integer.MAX_VALUE으로 설정합니다.

그리고 onBindViewHolder에서 list에서 반복해서 값을 꺼내도록 합니다. % 연산자는 나눈 나머지 값이기 때문에 list 사이즈가 4일 경우 0, 1, 2, 3이 반복해서 출력되기 때문에 list에서 반복적으로 값을 꺼낼 수 있습니다.

 

MyAdapter.java

import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    private Context context;
    private List<String> list;

    public MyAdapter(Context context, List<String> list) {
        this.context = context;
        this.list = list;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.row_item, parent, false);
        return new MyViewHolder(view);
    }

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

        int index = position % list.size();
        String item = list.get(index);
        holder.tvName.setText(String.format("%s", item));

        if (position % 2 == 0) {
            holder.imgBanner.setBackgroundColor(Color.YELLOW);
        } else {
            holder.imgBanner.setBackgroundColor(Color.GREEN);
        }
    }

    @Override
    public int getItemCount() {
        return Integer.MAX_VALUE;
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView tvName;
        ImageView imgBanner;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            tvName = itemView.findViewById(R.id.tvName);
            imgBanner = itemView.findViewById(R.id.imgBanner);
        }
    }
}

 

마지막으로 MainActivity는 Kotlin으로 작성해보았습니다.

여기에서는 list에 값을 넣고 viewpager에 위에서 작성한 adapter를 설정해줍니다

marginrhk page 이동시에 적용할 animation을 작성합니다.

그리고 currentItem을 1000으로 하는 이유는 무제한 스크롤 처럼 보이기 위해서는 0페이지 부터가 아니라 1000페이지 부터 시작해서 좌측으로 이동할 경우 999페이지로 이동하여 무제한 처럼 스크롤 되는 것 처럼 표현하기 위함입니다.

 

MainActivity.kt

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import kotlinx.android.synthetic.main.activity_main.*


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val items:List<String> = listOf(
            "item1",
            "item2",
            "item3",
            "item4"
        )


        val adapter = MyAdapter(this, items)

        viewPager2.adapter = adapter
        viewPager2.orientation = ViewPager2.ORIENTATION_HORIZONTAL
        viewPager2.offscreenPageLimit = 3
        viewPager2.currentItem = 1000

        val pageMargin = resources.getDimensionPixelOffset(R.dimen.pageMargin).toFloat()
        val pageOffset = resources.getDimensionPixelOffset(R.dimen.offset).toFloat()

        viewPager2.setPageTransformer({ page, position ->
            val myOffset = position * -(2 * pageOffset + pageMargin)
            if (position < -1) {
                page.setTranslationX(-myOffset)
            } else if (position <= 1) {
                val scaleFactor = Math.max(0.7f, 1 - Math.abs(position - 0.14285715f))
                page.setTranslationX(myOffset)
                page.setScaleY(scaleFactor)
                page.setAlpha(scaleFactor)
            } else {
                page.setAlpha(0f)
                page.setTranslationX(myOffset)
            }
        })


    }

}

 

이상 무제한 스크롤 ViewPager 입니다.

 

파일 첨부하였으니 받아 가실 때 댓글 하나씩 부탁드립니다 ^^

 

InfiniteViewPager.zip
0.13MB

 

댓글