'Auto scroll recyclerview slider

I am new to Android development. I am trying to create an auto scroll recyclerview slider which also supports user events such as next and previous buttons and manual scrolling.

Something like this: enter image description here

I have implemented the recyclerview and buttons events handling but I don't know how to implementing auto scroll, it is only scrolling from position 0 to the end and how to stop the auto scroll if the user swiped the slider manually or clicked on the buttons.

MainActivity.java

public class MainActivity extends AppCompatActivity {

RecyclerView mRecyclerView;
LinearLayoutManager layoutManager;
HorizontalSliderAdapter recyclerAdapter;
Button btnPrev;
Button btnNext;

Runnable runnable;
Handler handler;

public static final String LOGTAG = "slider";


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

    mRecyclerView = (RecyclerView) findViewById(R.id.horizontal_slider_recyclerview);
    setUpRecyclerView();
    autoScroll();

}

public void setUpRecyclerView() {

    final List<HorizontalSliderModel> RowItems = HorizontalSliderModel.getData();
    layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
    mRecyclerView.setLayoutManager(layoutManager);
    mRecyclerView.setHasFixedSize(true);
    recyclerAdapter = new HorizontalSliderAdapter(this, RowItems);
    mRecyclerView.setAdapter(recyclerAdapter);

    btnPrev = (Button) findViewById(R.id.bPrev);
    btnNext = (Button) findViewById(R.id.bNext);

    btnPrev.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mRecyclerView.getLayoutManager().scrollToPosition(layoutManager.findFirstVisibleItemPosition() - 1);
        }
    });
    btnNext.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mRecyclerView.getLayoutManager().scrollToPosition(layoutManager.findLastVisibleItemPosition() + 1);
        }
    });

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

            switch (newState) {

                case RecyclerView.SCROLL_STATE_IDLE:

                    float targetBottomPosition1 = mRecyclerView.getX();
                    float targetBottomPosition2 = mRecyclerView.getX() + mRecyclerView.getWidth();

                    Log.i(LOGTAG, "targetBottomPosition1 = " + targetBottomPosition1);
                    Log.i(LOGTAG, "targetBottomPosition2 = " + targetBottomPosition2);

                    View v1 = mRecyclerView.findChildViewUnder(targetBottomPosition1, 0);
                    View v2 = mRecyclerView.findChildViewUnder(targetBottomPosition2, 0);

                    float x1 = targetBottomPosition1;
                    if (v1 != null) {
                        x1 = v1.getX();
                    }

                    float x2 = targetBottomPosition2;
                    if (v2 != null) {
                        x2 = v2.getX();
                    }


                    Log.i(LOGTAG, "x1 = " + x1);
                    Log.i(LOGTAG, "x2 = " + x2);

                    float dx1 = Math.abs(mRecyclerView.getX() - x1);
                    float dx2 = Math.abs(mRecyclerView.getX() + mRecyclerView.getWidth() - x2);


                    Log.i(LOGTAG, "dx1 = " + dx1);
                    Log.i(LOGTAG, "dx2 = " + dx2);

                    float visiblePortionOfItem1 = 0;
                    float visiblePortionOfItem2 = 0;

                    if (x1 < 0 && v1 != null) {
                        visiblePortionOfItem1 = v1.getWidth() - dx1;
                    }

                    if (v2 != null) {
                        visiblePortionOfItem2 = v2.getWidth() - dx2;
                    }

                    Log.i(LOGTAG, "visiblePortionOfItem1 = " + visiblePortionOfItem1);
                    Log.i(LOGTAG, "visiblePortionOfItem2 = " + visiblePortionOfItem2);

                    int position = 0;
                    if (visiblePortionOfItem1 >= visiblePortionOfItem2) {
                        position = mRecyclerView.getChildAdapterPosition(mRecyclerView.findChildViewUnder(targetBottomPosition1, 0));
                    } else {

                        position = mRecyclerView.getChildAdapterPosition(mRecyclerView.findChildViewUnder(targetBottomPosition2, 0));
                    }
                    mRecyclerView.scrollToPosition(position);

                    break;

                case RecyclerView.SCROLL_STATE_DRAGGING:

                    break;

                case RecyclerView.SCROLL_STATE_SETTLING:

                    break;

            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        }
    });

}


public void autoScroll() {
    final int speedScroll = 2000;
    handler = new Handler();
    runnable = new Runnable() {
        int count = -1;

        @Override
        public void run() {
            if (count < mRecyclerView.getAdapter().getItemCount()) {
                mRecyclerView.smoothScrollToPosition(++count);
                handler.postDelayed(this, speedScroll);
            }
            if (count == mRecyclerView.getAdapter().getItemCount()) {
                mRecyclerView.setLayoutManager(new LinearLayoutManagerWithSmoothScroller(MainActivity.this));
                mRecyclerView.smoothScrollToPosition(--count);
                handler.postDelayed(this, speedScroll);
            }

        }

    };

    handler.post(runnable);
}
}


Solution 1:[1]

About the auto-scroll, I just started a new master/detail template in Android Studio.

Can you try to use this class as your recyclerView's layout manager ?

public class ScrollingLinearLayoutManager extends LinearLayoutManager {
private final int duration;

public ScrollingLinearLayoutManager(Context context, int orientation, boolean reverseLayout, int duration) {
    super(context, orientation, reverseLayout);
    this.duration = duration;
}

@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                   int position) {
    View firstVisibleChild = recyclerView.getChildAt(0);
    int itemHeight = firstVisibleChild.getHeight();
    int currentPosition = recyclerView.getChildLayoutPosition(firstVisibleChild);
    int distanceInPixels = Math.abs((currentPosition - position) * itemHeight);
    if (distanceInPixels == 0) {
        distanceInPixels = (int) Math.abs(firstVisibleChild.getY());
    }
    SmoothScroller smoothScroller = new SmoothScroller(recyclerView.getContext(), distanceInPixels, duration);
    smoothScroller.setTargetPosition(position);
    startSmoothScroll(smoothScroller);
}

private class SmoothScroller extends LinearSmoothScroller {
    private final float distanceInPixels;
    private final float duration;

    public SmoothScroller(Context context, int distanceInPixels, int duration) {
        super(context);
        this.distanceInPixels = distanceInPixels;
        this.duration = duration;
    }

    @Override
    public PointF computeScrollVectorForPosition(int targetPosition) {
        return ScrollingLinearLayoutManager.this
                .computeScrollVectorForPosition(targetPosition);
    }

    @Override
    protected int calculateTimeForScrolling(int dx) {
        float proportion = (float) dx / distanceInPixels;
        return (int) (duration * proportion);
    }
}

}

And set it like this

recyclerView.setAdapter(new SimpleItemRecyclerViewAdapter(DummyContent.ITEMS));
    recyclerView.setLayoutManager(new ScrollingLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false, 5000));

And trigger it this way

recyclerView.smoothScrollToPosition(recyclerView.getAdapter().getItemCount());

Solution 2:[2]

PagerSnapHelper solved my problem.

 binding.recyclerViewHomeAnnouncement.apply {
    layoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
    binding.recyclerViewHomeAnnouncement.layoutManager = layoutManager
    setHasFixedSize(true)
    itemAnimator = DefaultItemAnimator()
    adapter = homeAnnouncementAdapter
}

val snapHelper: SnapHelper = PagerSnapHelper()
snapHelper.attachToRecyclerView(binding.recyclerViewHomeAnnouncement)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Julien
Solution 2 Ça?la Akgül