RecyclerView/SnapHelper - 如何设置卡片的可变位置,以便它们根据位置以不同方式查看

RecyclerView/SnapHelper - How to set variable position of the cards so that they peek differently based on position

我是 android 的新手,因此 RV 和我正在尝试实现第一张和最后一张卡片不居中的布局,而是在它们之后和之前显示更多卡片。也许在这种情况下,我可以看到第二张卡片的 16dp 和倒数第二张卡片的相同情况,这使得第一张和最后一张卡片不居中。 但其余卡片每张 8dp,因此中间卡片居中显示。也许以某种方式为第二张和倒数第二张卡片使用 itemDecoration。

我能够按照此处的建议显示下一张和上一张卡片的部分内容,但这只会使所有卡片统一居中:

我尝试覆盖 getItemOffsets 但每次滚动到第一张或最后一张卡片时都会触发它,并且错误地将第二张和第二张卡片移动到最后一张卡片 而且当我滚动到它们时也没有正确地将它们居中。

  public static class MyItemDecoration extends RecyclerView.ItemDecoration {

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
      super.getItemOffsets(outRect, view, parent, state);

      final int itemPosition = parent.getChildAdapterPosition(view);
      if (itemPosition == RecyclerView.NO_POSITION) {
        return;
      }

      final int itemCount = state.getItemCount();
      if (itemCount > 0 && itemPosition == 1) {
        outRect.left -= 16;
        outRect.right -= 16;
      }

      else if (itemCount > 0 && itemPosition == itemCount - 1) {
        outRect.left += 16;
        outRect.right += 16;
      }
    }
  }

房车设置

 SnapHelper snapHelper = new PagerSnapHelper();
        RecyclerView rv = getBinding().rv;
        rv.setOnFlingListener(null);
        snapHelper.attachToRecyclerView(rv);

PagerSnapHelperRecyclerView 项目(包括装饰)居中,因此,除非装饰宽度平衡,否则它们不会始终居中.这可能就是您所看到的。

尝试以下装饰。此代码将 full-width 修饰应用于第一项的开头和最后一项的结尾;否则,使用一半装饰宽度。通过以这种方式设置装饰,您可以使左右装饰平衡的项目居中。

DividerItemDecoration decoration =
        new DividerItemDecoration(getApplicationContext(), HORIZONTAL) {
            private int mDecorationWidth = (int) (getResources().getDisplayMetrics().density * 8);

            @Override
            public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                                       RecyclerView.State state) {
                final int pos = parent.getChildAdapterPosition(view);
                if (pos == RecyclerView.NO_POSITION) {
                    return;
                }
                if (pos == 0) {
                    outRect.set(mDecorationWidth, 0, mDecorationWidth / 2, 0);
                } else if (pos == parent.getAdapter().getItemCount() - 1) {
                    outRect.set(mDecorationWidth / 2, 0, mDecorationWidth, 0);
                } else {
                    outRect.set(mDecorationWidth / 2, 0, mDecorationWidth / 2, 0);
                }
            }
        };

这是一个显示带有灰色垂直分隔线的结果的视频。

如果装饰效果已经令您满意,您可以覆盖 PagerSnapHelper 中的 calculateDistanceToFinalSnap() 以使除第一个和最后一个视图之外的所有视图居中,如下所示。参见 calculatedistancetofinalsnap()。一旦 PageSnapHelper 识别出要捕捉到的目标视图,就会调用 calculatedistancetofinalsnap() 来确定要移动多少像素以执行捕捉。在这里,我们移动的像素刚好足以使 RecyclerView 中的视图居中(没有装饰)。 PageSnapHelper 为第一个和最后一个项目做正确的事情,所以我们只为这些调用 super。

PagerSnapHelper pagerSnapHelper = new PagerSnapHelper() {  

    @Override  
  public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager,  
                                              @NonNull View targetView) {  
        LinearLayoutManager lm = (LinearLayoutManager) layoutManager;  
        int pos = mRecycler.getChildAdapterPosition(targetView);  
        // If first or last view, the default implementation works.  
  if (pos == 0 || pos == lm.getItemCount() - 1) {  
            return super.calculateDistanceToFinalSnap(layoutManager, targetView);  
        }  
        // Force centering in the view without its decorations. 
        // targetCenter is the location of the center of the view we want to center. 
        int targetCenter = targetView.getLeft() + targetView.getWidth() / 2;  
        // Distance is the number of pixels to move the target so that its center
        // lines up with the center of the RecyclerView (mRecycler.getWidth() / 2)       
        int distance = targetCenter - mRecycler.getWidth() / 2;  
        return new int[]{distance, 0};  
    }  
};

两种方法都行。