How to get the center item after RecyclerView snapped it to center?
Asked Answered
S

2

17

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?

Substructure answered 9/4, 2017 at 9:47 Comment(0)
L
27

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)
Lonni answered 9/4, 2017 at 9:51 Comment(1)
A very clean solution. ThanksSubdelirium
O
15

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);
    }
}
Oscine answered 4/8, 2017 at 16:36 Comment(1)
That medium article is very wholesome and clean!Swanky

© 2022 - 2024 — McMap. All rights reserved.