7

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);
}
}
YasserKaddour
  • 880
  • 11
  • 23
Mays Attari
  • 81
  • 1
  • 6
  • Why can't you use a Boolean to activate/deactivate the auto-scrolling whether that your user is clicking the manual scrolling buttons? – Julien Aug 07 '16 at 07:57
  • @Julien yes i will do that but i need to know how to implement the auto scrolling first. thanks for your suggestion – Mays Attari Aug 07 '16 at 08:14
  • Ok sorry. I didn't understand the auto-scrolling wasn't working. I'll try to run and fix the code when I have a computer with me – Julien Aug 07 '16 at 09:20
  • @Julien thanks in advance – Mays Attari Aug 07 '16 at 11:45
  • Where does your HorizontalSliderAdapter come from ? – Julien Aug 07 '16 at 17:33
  • @Julien i can't understand what do you mean.. do you want me to add its code? – Mays Attari Aug 07 '16 at 17:44
  • No just its import – Julien Aug 07 '16 at 17:46
  • @Julien all my imports import android.os.Bundle; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.widget.Button; import java.util.List; – Mays Attari Aug 07 '16 at 17:52
  • This answer can be helpful and its 100% working : [Auto Scroll RecyclerView](https://stackoverflow.com/a/56872365/6842344) – ParSa Jul 03 '19 at 14:36

2 Answers2

4

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());
Julien
  • 903
  • 7
  • 12
  • can you post your main activity class? plus i want to use my custom adapter.. sorry but as i said before i am new to android development – Mays Attari Aug 07 '16 at 19:23
  • I pushed it there https://github.com/julplee/ScrollingLinearLayoutManager. You can keep your adapter and change it with just the code you need from the ScrollingLinearLayoutManager – Julien Aug 08 '16 at 12:27
  • sorry for being late.. i will try implementing your code and show you the result – Mays Attari Aug 09 '16 at 07:09
0

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)
Cagla
  • 1
  • 2