web-dev-qa-db-ja.com

RecyclerViewが中央にスナップした後、中央のアイテムを取得するにはどうすればよいですか?

Google Playアプリの水平リストのように、スクロール後にアイテムを中央にスナップする水平RecyclerViewを実装しています。 This はレビューです。

私のコードは以下の通りです:

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);     

RecyclerViewが中央にスナップした後、中央のアイテム(位置)を取得するにはどうすればよいですか?このためのリスナーの実装はありませんか?また、アイテムビューをタッチしたときに中央にスナップしたい。これどうやってするの?

11
YUSMLE

ビューが必要な場合は、

 View view =  snapHelper.findSnapView(layoutManagaer);

ビューを取得すると、そのビューのデータセット上の位置を取得できるようになります。たとえば、

   mainMenu.getChildAdapterPosition(view)
11
Blackbelt

この方法を使用する方が良い:
https://medium.com/over-engineering/detecting-snap-changes-with-androids-recyclerview-snaphelper-9e9f5e95c424

元の投稿:
SnapHelperを使用しない場合でも、RecyclerView.OnScrollListenerによって中央の要素の位置を取得できます。

  1. MiddleItemFinderクラスをプロジェクトにコピーします。
  2. コールバックオブジェクトMiddleItemCallbackを作成します。

    MiddleItemFinder.MiddleItemCallback callback = 
            new MiddleItemFinder.MiddleItemCallback() {
                    @Override
                    public void scrollFinished(int middleElement) {
                        // interaction with middle item
                    }
    };
    
  3. RecyclerViewに新しいスクロールリスナーを追加します

    recyclerView.addOnScrollListener(
            new MiddleItemFinder(getContext(), layoutManager, 
                    callback, RecyclerView.SCROLL_STATE_IDLE));
    
  4. 最後のパラメーターまたはMiddleItemFinderコンストラクターはscrollStateです。

    • RecyclerView.SCROLL_STATE_IDLE –RecyclerViewは現在スクロールしていません。スクロールが終了しました。
    • RecyclerView.SCROLL_STATE_DRAGGING – RecyclerViewは現在、ユーザータッチ入力などの外部入力によってドラッグされています。
    • RecyclerView.SCROLL_STATE_SETTLING – RecyclerViewは現在、外部の制御下にないときに最終位置までアニメーション化しています。
    • MiddleItemFinder.ALL_STATES –すべての州をまとめたもの。
  5. たとえば、すべてのスクロールの最後よりも最後のコンストラクターパラメーターとしてRecyclerView.SCROLL_STATE_IDLEを選択した場合、コールバックオブジェクトは中央の要素位置を返します。

MiddleItemFinderクラス:

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);
    }
}
7
Mikhail Sharin