nikhil lohar
nikhil lohar

Reputation: 139

Infinite scrolling in viewpager2

How can we implement infinite scrolling in ViewPager2

As there is no OnPageChangeListener() in this pager. But there is setPageTransformer() Listener which get callback whenever we change page.

So any solution for viewpager2 problem

Note : I'm using recyclerview adapter for viewpager2

Upvotes: 4

Views: 9579

Answers (5)

ljk
ljk

Reputation: 1616

Since you mentioned you were using recyclerview adapter for viewpager2 have you tried writing it as you would while implementing infinite scroll in a recyclerview.
Basically you need to return Integer.MAX_VALUE in your adapter's getItemCount() method and whenever in onBindViewHolder you need actual item position always use position % yourList.size() . I've also added the size > 0 check in order to avoid crashes when list is empty and therefore this would otherwise throw a division by zero error.

Below is a sample adapter, you can use it as reference for your adapter and check if it works well for you. Hope this helps.

public class SampleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

private List<Sample> mSampleList;

public SampleAdapter(List<Sample> mSampleList) {
    this.mSampleList = mSampleList;
}

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View viewCommonItems = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.demo_view, parent, false);
    ItemViewHolder commonHolders = new ItemViewHolder(viewCommonItems);
    return commonHolders;

}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    ItemViewHolder viewHolder = (ItemViewHolder) holder;
    if(mSampleList.size()>0) {
        Sample sample = mSampleList.get(position % mSampleList.size());
        Glide.with(viewHolder.itemView.getContext()).load(sample.getImage())
                .into(viewHolder.ivImage);
    }
}

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

public class ItemViewHolder extends RecyclerView.ViewHolder {
    @BindView(R.id.iv_img)
    ImageView ivImage;
    public ItemViewHolder(@NonNull View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }
}

}

Upvotes: 3

Rafiqul Hasan
Rafiqul Hasan

Reputation: 3602

For infinite scrolling, you don't have to customise the view pager. The trick in the viewPager adapter. You can return Int.MAX value in getCount override method. The in the instantiateItem override function you can use item_position % item_size to get the actual item position. Code example is given below.

class AdsSliderAdapter(
private val bannerImageList: MutableList<SliderImagesItem>,
private val callback: SliderItemClickListener) :PagerAdapter() {

private var mContext: Context? = null
override fun instantiateItem(container: ViewGroup, position: Int): Any {
    mContext = container.context

    val view = LayoutInflater.from(container.context)
        .inflate(R.layout.item_ad_slider, container, false)

    val adImage: AppCompatImageView = view.ivAd
    mContext?.let {
        GlideApp.with(it).load(bannerImageList[position % bannerImageList.size].imageUrl)
            .into(adImage)
    }
    val viewPager = container as ViewPager
    viewPager.addView(view, 0)

    view.cardView.onClick { callback.onSliderImageClick(bannerImageList[position % bannerImageList.size]) }
    return view
}

override fun isViewFromObject(view: View, `object`: Any): Boolean {
    return view === `object`
}

override fun getCount(): Int {
    return if (bannerImageList.size > 0) {
        Int.MAX_VALUE
    } else {
        0
    }
}

override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
    val viewPager = container as ViewPager
    val view = `object` as View
    viewPager.removeView(view)
}

interface SliderItemClickListener {
    fun onSliderImageClick(item: SliderImagesItem)
}

}

Upvotes: 9

Hardik Talaviya
Hardik Talaviya

Reputation: 1496

Try below code

@Override
public void onPageScrollStateChanged (int state) {
    if (state == ViewPager.SCROLL_STATE_IDLE) {
        int curr = viewPager.getCurrentItem();
        int lastReal = viewPager.getAdapter().getCount() - 2;
        if (curr == 0) {
            viewPager.setCurrentItem(lastReal, false);
        } else if (curr > lastReal) {
            viewPager.setCurrentItem(1, false);
        }
    }
}

I hope this can help You!

Thank You.

Upvotes: 0

Kalpesh Rupani
Kalpesh Rupani

Reputation: 1049

Step 1 : Create EndlessScrollAdapter class

class EndlessScrollAdapter internal constructor(
    fm: FragmentManager,
    lifeCycle: Lifecycle
) : FragmentStateAdapter(fm, lifeCycle) {

    private val items = mutableListOf<Model>()
    val firstElementPosition = Int.MAX_VALUE / 2

    fun updateList(list: List<Model>) {
        items.apply {
            clear()
            addAll(list)
        }
        notifyDataSetChanged()
    }

    override fun getItemCount(): Int = if (items.isNotEmpty()) Int.MAX_VALUE else 0

    override fun createFragment(position: Int): Fragment = ViewPagerFragment(
        items[position.rem(items.size)])
}

Step : 2 Call from Activity or Fragment

viewPager2.adapter = endlessScrollAdapter
endlessScrollAdapter.apply {
  updateList(someModelList)
  viewPager2.setCurrentItem(this.firstElementPosition, false)
}

Literally It's not endless but from the user perspective it is, as he will never reach to the edge. The length of ViewPager2 is Int.MAX_VALUE, the start position is Int.MAX_VALUE/2 so user can scroll forward and backwards.

Upvotes: 5

Ajeett
Ajeett

Reputation: 812

You can use the code below

public class YourPagerAdapter extends FragmentStatePagerAdapter
{
    public static int COUNT_OF_LOOP = 1000;
    private ArrayList<Product> mProducts;


    public YourPagerAdapter(FragmentManager manager, ArrayList<Product> products)
    {
        super(manager);
        mProducts = products;
    }


    @Override
    public Fragment getItem(int position)
    {
        if (mProducts != null && mProducts.size() > 0)
        {
            position = position % mProducts.size(); 
            return MyFragment.newInstance(mProducts.get(position));
        }
        else
        {
            return MyFragment.newInstance(null);
        }
    }


    @Override
    public int getCount()
    {
        if (mProducts != null && mProducts.size() > 0)
        {
            return mProducts.size()*COUNT_OF_LOOP;
        }
        else
        {
            return 1;
        }
    }
} 

mAdapter = new YourPagerAdapter(getSupportFragmentManager(), mProducts);
mViewPager.setAdapter(mAdapter);
mViewPager.setCurrentItem(mViewPager.getChildCount() * YourPagerAdapter. COUNT_OF_LOOP / 2, false);

Upvotes: 0

Related Questions