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:
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);
}
}
To make RecyclerView auto scroll, we have to call smoothScrollToPosition every specified interval of time. We can use Flowable. interval to emit sequential Long value. To stop auto scroll if a user swipes RecyclerView, we can listen to the scroll state change.
You need to scroll the recycler view gradually using the post delay method of the handler. Now you need to initialize your handler. Don't forget to remove the listener in onStop() method and reinitialize at onResume() method. That's all for automatic scroll in recycler view.
You can use Scroll listener to detect scroll up or down changes in RecyclerView . RecycleView invokes the onScrollStateChanged() method before onScrolled() method. The onScrollStateChanged() method provides you the RecycleView's status: SCROLL_STATE_IDLE : No scrolling.
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());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With