0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ViewPager2でカルーセルを実装してみた(java編)

Posted at

こんにちはandroidでアプリ開発を学習中のみのむしと申します。
今回は、ViewPager2を使ってカルーセルを実装しましたので、
備忘録として残したいと思います。

レイアウトと実装方法について

今回は、CardViewとViewPager2を使ってmaterialdesign風にレイアウトしたいと思います。

また、参考サイトのほとんどがkotlinによる実装でしたので、
今回はjavaを用いた実装としたいと思います。

前提知識

offset:横にアイテム(今回はカード)をどれだけ見せるか設定する
margin:アイテム間の距離をどれだけとるか設定する

スクリーンショット 2023-02-04 133633.png

実装

activity.main.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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/cardViewPager"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:orientation="horizontal"
        android:layout_marginTop="40dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    
</androidx.constraintlayout.widget.ConstraintLayout>

calendar_cell.xml
<androidx.cardview.widget.CardView
    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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginStart="36dp"
    android:layout_marginEnd="36dp"
    app:cardBackgroundColor="@color/white"
    app:cardCornerRadius="16dp"
    app:cardElevation="7dp">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="300dp">

        <ImageView
            android:id="@+id/CardImage"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/image1"
            tools:ignore="ContentDescription" />
    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>

ポイントは、ViewPager2のorientationを
android:orientation="horizontal"
と指定し、横方向にスライドできるように指定しているところです。
縦方向のスライドを実装したい場合は、verticalと設定すれば可能です。

また、注意点としてはCardViewのheightとwidthはmatch_parentに設定しないと以下Exceptionが発生します。
java.lang.IllegalStateException: Pages must fill the whole ViewPager2 (use match_parent)

MainActivity.java
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.CompositePageTransformer;
import androidx.viewpager2.widget.MarginPageTransformer;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    //ViewPager2を取得する
    private ViewPager2 viewPager2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        viewPager2 = findViewById(R.id.cardViewPager);

        //作成したスライダーのリストを連携させる
        List<ImageModel> list = new ArrayList<>();
        list.add(new ImageModel(R.drawable.image1));
        list.add(new ImageModel(R.drawable.image2));
        list.add(new ImageModel(R.drawable.image3));
        list.add(new ImageModel(R.drawable.image4));
        list.add(new ImageModel(R.drawable.image5));

        viewPager2.setAdapter(new CardAdapter(list, viewPager2));
        viewPager2.setClipToPadding(false);
        viewPager2.setClipChildren(false);
        viewPager2.setOffscreenPageLimit(3);
        viewPager2.getChildAt(0).setOverScrollMode(RecyclerView.OVER_SCROLL_NEVER);

        CompositePageTransformer compositePageTransformer = new CompositePageTransformer();
        compositePageTransformer.addTransformer(new MarginPageTransformer(40));
        compositePageTransformer.addTransformer(new ViewPager2.PageTransformer() {
            @Override
            public void transformPage(@NonNull View page, float position) {
                //カルーセルを作成する処理
                float offset = position * (dpFormat(2) * dpFormat(10) + dpFormat(10));
                page.setTranslationX(-offset);
            }
        });
        //scrollした際のAnimationを設定する
        viewPager2.setPageTransformer(compositePageTransformer);

    }

    //pxをdpに変換する
    private int dpFormat(int dp) {
        DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics();
        return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
    }

}
CalendarAdapter.java
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import java.util.List;

public class CardAdapter extends RecyclerView.Adapter<CardAdapter.MyCardViewAdapter> {

    private final List<ImageModel> Item;
    ViewPager2 viewPager2;

    public CardAdapter(List<ImageModel> item, ViewPager2 viewPager2) {
        this.Item = item;
        this.viewPager2 = viewPager2;
    }

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

    @Override
    public void onBindViewHolder(@NonNull MyCardViewAdapter holder, int position) {
      holder.setImageview(Item.get(position));
    }

    @Override
    public int getItemCount() {
        return Item.size();
    }

    public static class MyCardViewAdapter extends RecyclerView.ViewHolder{

        private final ImageView Imageview;
        public MyCardViewAdapter(@NonNull View itemView) {
            super(itemView);
            Imageview = itemView.findViewById(R.id.CardImage);
        }

        private void setImageview(@NonNull ImageModel adapter){
            Imageview.setImageResource(adapter.getImage());
        }
    }
}

ImageModel.java

public class ImageModel {

    private final int image;

    ImageModel (int image){
     this.image = image;
    }

    public int getImage() {
        return image;
    }
}

応用編

応用編としてチラ見させるアイテムのセルにアニメーションをつけるバージョン

MainActivity.java
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.CompositePageTransformer;
import androidx.viewpager2.widget.MarginPageTransformer;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        //ViewPager2を取得する
        ViewPager2 viewPager2 = findViewById(R.id.cardViewPager);

        //作成したスライダーのリストを連携させる
        List<ImageModel> list = new ArrayList<>();
        list.add(new ImageModel(R.drawable.image1));
        list.add(new ImageModel(R.drawable.image2));
        list.add(new ImageModel(R.drawable.image3));
        list.add(new ImageModel(R.drawable.image4));
        list.add(new ImageModel(R.drawable.image5));

        viewPager2.setAdapter(new CardAdapter(list, viewPager2));
        viewPager2.setClipToPadding(false);
        viewPager2.setClipChildren(false);
        viewPager2.setOffscreenPageLimit(3);
        viewPager2.getChildAt(0).setOverScrollMode(RecyclerView.OVER_SCROLL_NEVER);

        CompositePageTransformer compositePageTransformer = new CompositePageTransformer();
        compositePageTransformer.addTransformer(new MarginPageTransformer(40));
        compositePageTransformer.addTransformer(new ViewPager2.PageTransformer() {
            @Override
            public void transformPage(@NonNull View page, float position) {
                //カルーセルを作成する処理
                float offset = position * (dpFormat(2) * dpFormat(10) + dpFormat(10));
                float r = 1-Math.abs(position);
                page.setTranslationX(-offset);
                page.setScaleY(0.85f + r * 0.15f);
            }
        });
        //scrollした際のAnimationを設定する
        viewPager2.setPageTransformer(compositePageTransformer);

    }

    //PxをDpに変換する
    private int dpFormat(int dp) {
        DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics();
        return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
    }

}

参考サイト https://qiita.com/nakashimaakio/items/2e908483949874728f25 https://satoshun.github.io/2019/08/viewpager2-like-a-carousel/
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?