2

I am working on an Android app that runs on only one devicerunning KitKat.

The smooth scrolling feature for a RecylerView I used that was working on other physical tablets and genymotion has unfortunately stopped working on the one device it needs to work on.

Instead of scrolling to a certain position it passes over the target position and scrolls all the way to the bottom and looks really bad.

I am able to track down the error to the abstract SmoothScroller in the RecyclerView class.

           if (getChildPosition(mTargetView) == mTargetPosition) {
                onTargetFound(mTargetView, recyclerView.mState, mRecyclingAction);
                mRecyclingAction.runIfNecessary(recyclerView);
                stop();
            } else {
                Log.e(TAG, "Passed over target position while smooth scrolling.");
                mTargetView = null;
            }

I was using a SnappingLinearLayoutManager that I found online, but swapped it out with the normal LinearLayoutManager from Android, and still am having the same problem.

The list is 7 items long (user can see 4 at a time) and I scroll to the 5th item (position 4) item.

When I scroll to the 3rd I don't receive this error.

Also after I scroll the list up and down once, the error stops happening.

EDIT: I am able to use layoutManager.scrollToPositionWithOffset(); But I am trying to do this with the smooth scroll animation.

Here is some of my code and details:

private void setupMainRecyclerViewWithAdapter() {
    mainLayoutManager = new SnappingLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
    mainListRecyclerView.setLayoutManager(mainLayoutManager);

    settingsMainListAdapter = new SettingsListAdapter(SettingsActivity.this,
            settingsPresenter.getSettingsItems(),
            settingsPresenter);

    mainListRecyclerView.setAdapter(settingsMainListAdapter);

    mainListRecyclerView.addItemDecoration(new BottomOffsetDecoration(EXTRA_VERTICAL_SCROLLING_SPACE));
}

@Override
public void scrollMainList(boolean listAtTop) {
    if(listAtTop) {
        mainListRecyclerView.smoothScrollToPosition(4);
        moveMainMoreButtonAboveList();
    } else {
        mainListRecyclerView.smoothScrollToPosition(0);
        moveMainMoreButtonBelowList();
    }
}
SamIAmHarris
  • 2,158
  • 3
  • 16
  • 19
  • 1
    Try using `layoutManager.scrollToPosition(index);` instead – BNK Dec 08 '16 at 04:39
  • Sorry I should say that I am able to use layoutManager.scrollToPositionWithOffset(); But I am trying to do this with the smooth scroll animation. Good catch @BNK . I will add that edit to my question. – SamIAmHarris Dec 08 '16 at 04:44
  • 2
    Perhaps they can help https://mcochin.wordpress.com/2015/05/13/android-customizing-smoothscroller-for-the-recyclerview/ and https://blog.stylingandroid.com/scrolling-recycler-view-part-2/ – BNK Dec 08 '16 at 07:42
  • Yea I tried implementing the solution from the mcochin blog post, but ran into the same "Passed over target position while smooth scrolling." error. I will look into the other one. Thanks for the help! – SamIAmHarris Dec 08 '16 at 13:59

4 Answers4

7

If you call recyclerView.smoothScrollToPosition(pos) will be called immediately on the UI thread and if recyclerView's Adapter is too much busy to generating view items then the calling of smoothScrollToPosition will be missed then because recyclerView has no data to smooth scroll. So it's better to do that in a background thread by recyclerView.post(). By calling this it goes into the Main thread queue and gets executed after the other pending tasks are finished.

Therefore you should do something like this which worked for my case:

recyclerView.post(new Runnable() {
    @Override
    public void run() {
        recyclerView.smoothScrollToPosition(pos);
    }
});
Gk Mohammad Emon
  • 6,084
  • 3
  • 42
  • 42
4

Well, I realize it's too late, however I tried some different solutions and found one...

in custom LinearSmoothScroller I override updateActionForInterimTarget

@Override protected void updateActionForInterimTarget(Action action) { action.jumpTo(position); }

It's appears not very smooth, but not instant in contrast with scrollToPositionWithOffset.

2

Just add one line for smooth scroll

recyclerView.setNestedScrollingEnabled(false);

it will work fine

0

Take a look at hasPendingAdapterUpdates(). You can use this along with a delay() for coroutines or Thread.sleep() to enable the backing data to be available before doing the scroll.

Clocker
  • 1,316
  • 2
  • 19
  • 29