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

17,965

Solution 1

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

![enter image description here

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

enter image description here

Solution 2

Using ViewPager2 (that has RecyclerView in it).

vp2 is instance of ViewPager2

This worked for me:

RecyclerView rv = (RecyclerView) vp2.getChildAt(0);
rv.setPadding(80, 0, 80, 0);
rv.setClipToPadding(false);

I used FragmentStateAdapter for it and overriding getItemId() and containsItem() for add/remove fragments.

result is here:

enter image description here

Share:
17,965
mdDroid
Author by

mdDroid

I am Software Developer interested in JAVA and Android ; Wish to be expert in Android Apps.Currently working as Sr. Software Engineer (Android) Enthusiastic about Java Programming, and Android ,Love to explore IT ,Keen learner, Self-motivated ,Innovative, Enjoys R&amp;D. Aim: To take up challenges in Software Development and create value &amp; recognition on work place by producing the best result for the organization through synchronize, hard work &amp; determination. Specialties: Android (Native App with ADT), JAVA J2EE Spring , Web technology (HTML, CSS, JSP),MySQL, Sqlite ,Oracle

Updated on June 21, 2022

Comments

  • mdDroid
    mdDroid about 2 years

    Want to create the view pager same as following UI, applied custom transformer but not working.

    enter image description here

    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));
        }
    }
    }
    
  • Albert Vila Calvo
    Albert Vila Calvo almost 5 years
    Thanks for this! I've been trying to implement the carousel with ViewPager2 for a few hours with no success.
  • Albert Vila Calvo
    Albert Vila Calvo almost 5 years
    I don't think that you need to set clipToPadding="false" on the ViewPager because it doesn't have any padding. Also, I don't think that you need clipChildren="false" either since you are not scaling any item more than 100% (ie. you're not drawing outside of the ViewPager). On your GitHub code nothing changes if I remove them. I'd suggest to remove this attributes if they are useless.
  • AskNilesh
    AskNilesh almost 5 years
    @AlbertVilaCalvo okay i will remove that
  • Albert Vila Calvo
    Albert Vila Calvo almost 5 years
    Another thing: you are setting offscreenPageLimit to 3. This means that there are 3 items retained on each side (total 6), even though you are only showing 1 extra item at each side. Unless you have the need to do so, you can lower this number to 2 or even 1 (everything keeps working fine).
  • Danilo Lemes
    Danilo Lemes over 4 years
    This code is related to ViewPager, OP is using ViewPager2
  • Shubham AgaRwal
    Shubham AgaRwal almost 3 years
    somehow this is leaving empty blank space after some scrolling