Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the center item after RecyclerView snapped it to center?

I'm implementing a horizontal RecyclerView that snap items to center after scrolling, like Google play App horizontal lists. This is a review.

My code is below:

MainMenuAdapter mainMenuAdapter = new MainMenuAdapter(this, mDataset);

final LinearLayoutManager layoutManagaer = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);

RecyclerView mainMenu = (RecyclerView) findViewById(R.id.main_menu);
mainMenu.setLayoutManager(layoutManagaer);
mainMenu.setAdapter(mainMenuAdapter);

final SnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(mainMenu);     

How I can get the center item (position) after RecyclerView snapped it to center? Isn't there any listener implementation for this? Also, when an item view be touched, I want to snap it to center. How can I do this?

like image 602
YUSMLE Avatar asked Apr 09 '17 09:04

YUSMLE


People also ask

How do you center a recycler view?

Take LinearLayout in your RecyclerView 's item row layout then give android:layout_gravity="center" to LinearLayout . For each row of images you have to take different LinearLayout .

How do I use SnapHelper in RecyclerView?

You can now just use a SnapHelper. If you want a center-aligned snapping behavior similar to ViewPager then use PagerSnapHelper: SnapHelper snapHelper = new PagerSnapHelper(); snapHelper. attachToRecyclerView(recyclerView);

What is snapping in RecyclerView?

SnapHelper is a helper class that helps in snapping any child view of the RecyclerView. For example, you can snap the firstVisibleItem of the RecyclerView as you must have seen in the play store application that the firstVisibleItem will be always completely visible when scrolling comes to the idle position.

What is a SnapHelper?

SnapHelper is a helper class that is used to snap any child of our RecyclerView. With the help of this class, we can display the specific number of RecyclerView items on our screen, and we can avoid the RecyclerView children's display inside our RecyclerView.


2 Answers

if you need the View, you can call

 View view =  snapHelper.findSnapView(layoutManagaer);

once you have the View, you should be able to get the position on the dataset for that View. For instance using

   mainMenu.getChildAdapterPosition(view)
like image 89
Blackbelt Avatar answered Oct 22 '22 03:10

Blackbelt


Better to use this method:
https://medium.com/over-engineering/detecting-snap-changes-with-androids-recyclerview-snaphelper-9e9f5e95c424

Original post:
Even if you are not going to use SnapHelper you can get the central element position by RecyclerView.OnScrollListener.

  1. Copy MiddleItemFinder class to your project.
  2. Create callback object MiddleItemCallback.

    MiddleItemFinder.MiddleItemCallback callback = 
            new MiddleItemFinder.MiddleItemCallback() {
                    @Override
                    public void scrollFinished(int middleElement) {
                        // interaction with middle item
                    }
    };
    
  3. Add new scroll listener to your RecyclerView

    recyclerView.addOnScrollListener(
            new MiddleItemFinder(getContext(), layoutManager, 
                    callback, RecyclerView.SCROLL_STATE_IDLE));
    
  4. The last parameter or MiddleItemFinder constructor is scrollState.

    • RecyclerView.SCROLL_STATE_IDLE – The RecyclerView is not currently scrolling. Scroll finished.
    • RecyclerView.SCROLL_STATE_DRAGGING – The RecyclerView is currently being dragged by outside input such as user touch input.
    • RecyclerView.SCROLL_STATE_SETTLING – The RecyclerView is currently animating to a final position while not under outside control.
    • MiddleItemFinder.ALL_STATES – All states together.
  5. For example, if you choose RecyclerView.SCROLL_STATE_IDLE as the last constructor parameter than in the end of all scroll the callback object will return you the middle element position.

MiddleItemFinder class:

public class MiddleItemFinder extends RecyclerView.OnScrollListener {

    private
    Context context;

    private
    LinearLayoutManager layoutManager;

    private
    MiddleItemCallback callback;

    private
    int controlState;

    public
    static final int ALL_STATES = 10;

    public MiddleItemFinder(Context context, LinearLayoutManager layoutManager, MiddleItemCallback callback, int controlState) {
    this.context = context;
    this.layoutManager = layoutManager;
    this.callback = callback;
    this.controlState = controlState;
    }

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

        if (controlState == ALL_STATES || newState == controlState) {

            int firstVisible = layoutManager.findFirstVisibleItemPosition();
            int lastVisible = layoutManager.findLastVisibleItemPosition();
            int itemsCount = lastVisible - firstVisible + 1;

            int screenCenter = context.getResources().getDisplayMetrics().widthPixels / 2;

            int minCenterOffset = Integer.MAX_VALUE;

            int middleItemIndex = 0;

            for (int index = 0; index < itemsCount; index++) {

                View listItem = layoutManager.getChildAt(index);

                if (listItem == null)
                    return;

                int leftOffset = listItem.getLeft();
                int rightOffset = listItem.getRight();
                int centerOffset = Math.abs(leftOffset - screenCenter) + Math.abs(rightOffset - screenCenter);

                if (minCenterOffset > centerOffset) {
                    minCenterOffset = centerOffset;
                    middleItemIndex = index + firstVisible;
                }
            }

            callback.scrollFinished(middleItemIndex);
        }
    }

    public interface MiddleItemCallback {

        void scrollFinished(int middleElement);
    }
}
like image 14
Mikhail Sharin Avatar answered Oct 22 '22 04:10

Mikhail Sharin