51

I'm using a RecyclerView in my Android app. I've many cardviews in my RecyclerView, such that only 1 cardview is displayed to the user at a time. The user has to swipe to see the next card.

I faced an issue that when user makes a swipe, the recyclerview gets scrolled to the end. Instead, what I need is when the user swipes, display the next card to the user as mentioned in this post.

How to make swipe on horizontal recyclerview bring only the next item into view - Android

SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);

I tried the answer mentioned in the above link. But I'm getting an exception when the user makes a swipe.

Please help me resolve it.

Error

java.lang.IllegalStateException: An instance of OnFlingListener already set.
    at android.support.v7.widget.SnapHelper.setupCallbacks(SnapHelper.java:114)
    at android.support.v7.widget.SnapHelper.attachToRecyclerView(SnapHelper.java:102)
    at com.abc.ui.trm.TrCard.setupCardView(TrCard.java:62)
    at com.abc.ui.trm.TrCard.setupCardView(TrCard.java:29)
    at com.abc.ui.core.card.BaseCardView.processCardView(BaseCardView.java:134)
    at com.abc.ui.card.CardRecyclerAdapter.onViewAttachedToWindow(CardRecyclerAdapter.java:398)
    at android.support.v7.widget.RecyclerView.dispatchChildAttached(RecyclerView.java:6758)
    at android.support.v7.widget.RecyclerView$5.addView(RecyclerView.java:696)
    at android.support.v7.widget.ChildHelper.addView(ChildHelper.java:107)
    at android.support.v7.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:7697)
    at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:7655)
    at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:7643)
    at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1539)
    at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1488)
    at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:585)
    at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3506)
    at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3254)
    at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3767)
    at android.view.View.layout(View.java:18799)
    at android.view.ViewGroup.layout(ViewGroup.java:5952)
    at com.abc.ui.core.refresh.LegacySwipeRefreshLayout.onLayout(LegacySwipeRefreshLayout.java:337)
    at android.view.View.layout(View.java:18799)
    at android.view.ViewGroup.layout(ViewGroup.java:5952)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
    at android.view.View.layout(View.java:18799)
    at android.view.ViewGroup.layout(ViewGroup.java:5952)
    at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1079)
    at android.view.View.layout(View.java:18799)
    at android.view.ViewGroup.layout(ViewGroup.java:5952)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
    at android.view.View.layout(View.java:18799)
    at android.view.ViewGroup.layout(ViewGroup.java:5952)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
    at android.view.View.layout(View.java:18799)
    at android.view.ViewGroup.layout(ViewGroup.java:5952)
    at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1193)
    at android.view.View.layout(View.java:18799)
    at android.view.ViewGroup.layout(ViewGroup.java:5952)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
    at android.view.View.layout(View.java:18799)
    at android.view.ViewGroup.layout(ViewGroup.java:5952)
    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
    at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
    at android.view.View.layout(View.java:18799)
    at android.view.ViewGroup.layout(ViewGroup.java:5952)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
    at com.android.internal.policy.DecorView.onLayout(DecorView.java:822)
    at android.view.View.layout(View.java:18799)
    at android.view.ViewGroup.layout(ViewGroup.java:5952)
Community
  • 1
  • 1
Nitya
  • 583
  • 2
  • 5
  • 10

6 Answers6

105

I managed to sovle this with adding this line

recyclerView.setOnFlingListener(null); 

before

snapHelper.attachToRecyclerView(recyclerView);
Mohamed ALOUANE
  • 5,349
  • 6
  • 29
  • 60
  • 1
    easy and simple solution. It might be a hacky solution, but as far as I see the complicated implementation of SnapHelper, it´s the best solution and should be the accepted answer. – Opiatefuchs Jul 12 '17 at 11:58
  • Adding both clearOnScrollListeners() and setOnFlingListener(null) solved my problem – Kiran Dec 07 '17 at 10:33
  • 1
    I got this error if I set the data again to recycler view, adding `setOnFlingListener` effected the `recyclerView.addOnScrollListener`. it wasn't triggering after data set second time. So I called my fragment again by setting arguments to it. – Prabs Jul 06 '18 at 12:07
  • @NoumanCh Have you already resolved your issue? And do you have an addition to how you solved it for us? – Rik van Velzen Sep 28 '18 at 11:33
  • @RikvanVelzen yes, I had resolved it through some ways I don't remember now. – Nouman Ch Sep 28 '18 at 11:36
30

You can check for OnFlingListener on the RecyclerView first before you add it

if (recycler.getOnFlingListener() == null)
        snapHelper.attachToRecyclerView(recycler);
saintjab
  • 1,626
  • 20
  • 31
10

All you have to do is place

SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);

inside onCreateViewHolder instead of onBindViewHolder

Bassel Mourjan
  • 3,604
  • 3
  • 26
  • 37
9

This happens because you're setting the SnapPagerHelper twice somehow. Note that if you have a RecyclerView inside another RecyclerView, this should only happen in each other's constructors or Kotlin's init {} block (once per item).
My case is quite similar to yours since I have a big vertical RecyclerView and a small RecyclerView within.

Code that will cause the exception:

 fun bind(value: ArrayList<Item>) {
    listAdapter = ItemCellDelegate(value)

    val manager = LinearLayoutManager(itemView.context)
    manager.orientation = LinearLayoutManager.HORIZONTAL

    horizontalRecyclerView?.apply {
        layoutManager = manager
        adapter = listAdapter
        setHasFixedSize(true)
    }

    val snapHelper: SnapHelper = PagerSnapHelper()
    snapHelper.attachToRecyclerView(horizontalRecyclerView)

}

Correct code using init {} block:

init {
    val snapHelper: SnapHelper = PagerSnapHelper()
    snapHelper.attachToRecyclerView(horizontalRecyclerView)
}
pamobo0609
  • 812
  • 10
  • 21
1

something like this:

override fun onAttachedToWindow(view: RecyclerView) {
    super.onAttachedToWindow(view)
    view.onFlingListener = null;
    StartSnapHelper().attachToRecyclerView(view)
}
Iman Marashi
  • 5,593
  • 38
  • 51
1

I also getting Error in neasted RecyclerView or inner RecyclerView, I managed to sovle this with adding this line.

holder.rv_sub_loaction.setOnFlingListener(null);

Whole recyclerView set code:

subLocationModels.addAll(response.body());
            recyclerDataAdapter = new SubSubLocationAdapter(subLocationModels);
            SnapHelper helper = new LinearSnapHelper();
            LinearLayoutManager layoutManager = new  GridLayoutManager(mContext, 2, GridLayoutManager.HORIZONTAL, false);
            holder.rv_sub_loaction.setLayoutManager(layoutManager);
            holder.rv_sub_loaction.setOnFlingListener(null);
            holder.rv_sub_loaction.setAdapter(recyclerDataAdapter);
            helper.attachToRecyclerView(holder.rv_sub_loaction);
            holder.rv_sub_loaction.setHasFixedSize(true);