簡體   English   中英

RecyclerView SnapHelper查找被捕捉項目的確切位置

[英]RecyclerView SnapHelper find the exact position of snapped item

如何找到捕捉的項目的索引? 我嘗試使用:

recyclerView.setOnFlingListener(new RecyclerView.OnFlingListener() {
        @Override
        public boolean onFling(int velocityX, int velocityY) {
            Log.i(TAG, "initRecyclerView: SNAPPING TO:" +snapHelper.findTargetSnapPosition(recyclerView.getLayoutManager(),velocityX,velocityY)%songs.size());
            return false;
        }
    });

但它確實不准確,有時返回-1。

我試過了 :

snapHelper.findSnapView(recyclerView.getLayoutManager());

但它返回一個視圖,我認為我無法在recyclerview中獲取視圖的索引。 (我錯了嗎?)

我對方法何時返回索引沒有偏愛(在刷新完成之前或之后)。

ps:我的recyclerview有一個自定義的ZoomingLayoutManager(用於輪播效果)。 也許它正在改變視圖的大小,這會導致snapHelper錯誤? 我知道snapHelper在childViews可見的平均高度和寬度上工作

public class ZoomingLayoutManager extends LinearLayoutManager {
    private final float mShrinkAmount = 0.5f;
    private final float mShrinkDistance = 0.9f;

    public ZoomingLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    @Override
    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
        int orientation = getOrientation();
        if (orientation == HORIZONTAL) {
            int scrolled = super.scrollHorizontallyBy(dx, recycler, state);

            float midpoint = getWidth() / 2.f;
            float d0 = 0.f;
            float d1 = mShrinkDistance * midpoint;
            float s0 = 1.f;
            float s1 = 1.f - mShrinkAmount;
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                float childMidpoint =
                        (getDecoratedRight(child) + getDecoratedLeft(child)) / 2.f;
                float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
                float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
                child.setScaleX(scale);
                child.setScaleY(scale);
            }
            return scrolled;
        } else {
            return 0;
        }

    }

    @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        int orientation = getOrientation();
        if (orientation == VERTICAL) {
            int scrolled = super.scrollVerticallyBy(dy, recycler, state);
            float midpoint = getHeight() / 2.f;
            float d0 = 0.f;
            float d1 = mShrinkDistance * midpoint;
            float s0 = 1.f;
            float s1 = 1.f - mShrinkAmount;
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                float childMidpoint =
                        (getDecoratedBottom(child) + getDecoratedTop(child)) / 2.f;
                float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
                float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
                child.setScaleX(scale);
                child.setScaleY(scale);
            }
            return scrolled;
        } else {
            return 0;
        }
    }
}

如果是真的,我該如何覆蓋snapHelper方法以找到更准確的位置? 還是我只是缺少明顯的東西!

您可以嘗試這樣的事情; 在我的情況下,只有一個項目位於屏幕中央,左側和右側項目僅部分可見,並且效果很好。

添加一個onScrollListener並等待SCROLL_STATE_SETTLING狀態,然后獲取FirstCompletelyVisibleItemPosition

注意:我使用的Handler具有1秒的延遲 ,如下所示,您可以刪除該部分,而僅使用findFirstCompletelyVisibleItemPosition() 用於確定滾動狀態。

    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            if (newState == RecyclerView.SCROLL_STATE_SETTLING) {
                new Handler().postDelayed(() -> {
                    int pos = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
                    if (pos >= 0) {
                        // do your thing, the pos value must be your first fully visible or snapped view
                    }
                }, 1000);

            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);

        }
    });

因此,感謝OğuzhanDöngül的技巧,我使用findFirstCompletelyVisibleItemPosition()找出了位置,但是在“何時”調用該方法很重要。 滾動完成后,recyclerview的狀態更改為“ idle”,因此感謝您可以使用提供的方法獲取第一個完全可見視圖的確切位置。 但是,如果第一個可見視圖的位置不是您想要的,並且您希望視圖的位置在屏幕中間怎么辦?

好吧,您可以通過計算中間項和屏幕邊框之間的屏幕中多少個視圖完全可見來添加偏移量(它實際上很簡單)

因此,代碼:

 recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if(newState==RecyclerView.SCROLL_STATE_IDLE){
                int pos = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
                if (pos >= 0) {
                    int position=pos+ bigScreenOffset;
                    // do your thing, the position value is the exact index of the middle item
                }
            }
        }
    });

bigScreenOffset的計算公式為:

        bigScreenOffset= ( Utility.getDisplaySize(this,true,true)/200)/2;

我在實用程序類中處理dp | px中width | height的自定義方法是:

 public static int getDisplaySize(Context context, boolean width, boolean dp) {
    DisplayMetrics displayMetrics = new DisplayMetrics();
    ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    if (width) {
        if (dp)
            return (int) convertPixelsToDp(displayMetrics.widthPixels, context);
        else
            return displayMetrics.widthPixels;
    } else {
        if (dp)
            return (int) convertPixelsToDp(displayMetrics.heightPixels, context);
        else
            return displayMetrics.heightPixels;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM