View Pager with previous and next item smaller in size with infinite scroll

android, android-animation, android-transitions, android-viewpager, android-viewpager2

Solution

UPDATE - if you want to make current page zoom use below `PageTransformer`

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;

public class JavaActivity extends AppCompatActivity {

    ViewPager2 myViewPager2;
    MyAdapter MyAdapter;

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

        myViewPager2 = findViewById(R.id.viewpager);

        MyAdapter = new MyAdapter(this);
        myViewPager2.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
        myViewPager2.setAdapter(MyAdapter);
        myViewPager2.setOffscreenPageLimit(3);

        float pageMargin = getResources().getDimensionPixelOffset(R.dimen.pageMargin);
        float pageOffset = getResources().getDimensionPixelOffset(R.dimen.offset);

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

    }
}

OUTPUT

NOTE: you can download complete code from my GitHub repositories

Try this way

JavaActivity

import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewCompat;
import androidx.viewpager2.widget.ViewPager2;

public class JavaActivity extends AppCompatActivity {

    ViewPager2 myViewPager2;
    MyAdapter MyAdapter;

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

        myViewPager2 = findViewById(R.id.viewpager);

        MyAdapter = new MyAdapter(this);
        myViewPager2.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
        myViewPager2.setAdapter(MyAdapter);
        myViewPager2.setOffscreenPageLimit(3);

        float pageMargin= getResources().getDimensionPixelOffset(R.dimen.pageMargin);
        float pageOffset = getResources().getDimensionPixelOffset(R.dimen.offset);
        
        myViewPager2.setPageTransformer(new ViewPager2.PageTransformer() {
            @Override
            public void transformPage(@NonNull View page, float position) {
                float myOffset = position * -(2 * pageOffset + pageMargin);
                if (myViewPager2.getOrientation() == ViewPager2.ORIENTATION_HORIZONTAL) {
                    if (ViewCompat.getLayoutDirection(myViewPager2) == ViewCompat.LAYOUT_DIRECTION_RTL) {
                        page.setTranslationX(-myOffset);
                    } else {
                        page.setTranslationX(myOffset);
                    }
                } else {
                    page.setTranslationY(myOffset);
                }
            }
        });
    }
}

activity_java layout file

    <?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:orientation="vertical"
                  tools:context=".JavaActivity">
    
        <androidx.viewpager2.widget.ViewPager2
                android:id="@+id/viewpager"
                android:clipToPadding="false"
                android:clipChildren="false"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
    
    </LinearLayout>

>

MyAdapter

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;

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

    private Context context;

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

    @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) {
        holder.tvName.setText(String.format("Row number%d", position));
        if (position % 2 ==0){
            holder.imgBanner.setBackgroundColor(Color.RED);
        }else {
            holder.imgBanner.setBackgroundColor(Color.GREEN);
        }
    }

    @Override
    public int getItemCount() {
        return 15;
    }

    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);
        }
    }
}

row_item layout

<?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>

OUTPUT

Problem

Want to create the view pager same as following UI, applied custom transformer but not working. ViewPager.java ``` public class MyViewPager extends ViewPager implements ViewPager.PageTransformer { public static final String TAG = "MyViewPager"; private float MAX_SCALE = 0.0f; private int mPageMargin; private boolean animationEnabled=true; private boolean fadeEnabled=false; private float fadeFactor=0.5f; public MyViewPager(Context context) { this(context, null); } public MyViewPager(Context context, AttributeSet attrs) { super(context, attrs); // clipping should be off on the pager for its children so that they can scale out of bounds. setClipChildren(false); setClipToPadding(false); // to avoid fade effect at the end of the page setOverScrollMode(2); setPageTransformer(false, this); setOffscreenPageLimit(3); mPageMargin = dp2px(context.getResources(), 50); setPadding(mPageMargin, mPageMargin, mPageMargin, mPageMargin); } public int dp2px(Resources resource, int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resource.getDisplayMetrics()); } public void setAnimationEnabled(boolean enable) { this.animationEnabled = enable; } public void setFadeEnabled(boolean fadeEnabled) { this.fadeEnabled = fadeEnabled; } public void setFadeFactor(float fadeFactor) { this.fadeFactor = fadeFactor; } @Override public void setPageMargin(int marginPixels) { mPageMargin = marginPixels; // setPadding(mPageMargin, mPageMargin, mPageMargin, mPageMargin); } @Override public void transformPage(View page, float position) { if (mPageMargin <= 0|| !animationEnabled) return; page.setPadding(mPageMargin / 3, mPageMargin / 3, mPageMargin / 3, mPageMargin / 3); if (MAX_SCALE == 0.0f && position > 0.0f && position < 1.0f) { MAX_SCALE = position; } position = position - MAX_SCALE; float absolutePosition = Math.abs(position); if (position <= -1.0f || position >= 1.0f) { if(fadeEnabled) page.setAlpha(fadeFactor); // Page is not visible -- stop any running animations } else if (position == 0.0f) { // Page is selected -- reset any views if necessary page.setScaleX((1 + MAX_SCALE)); page.setScaleY((1 + MAX_SCALE)); page.setAlpha(1); } else { page.setScaleX(1 + MAX_SCALE * (1 - absolutePosition)); page.setScaleY(1 + MAX_SCALE * (1 - absolutePosition)); if(fadeEnabled) page.setAlpha( Math.max(fadeFactor, 1 - absolutePosition)); } } } ```

Original source