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

Ram*_*mil 1 android android-layout android-recyclerview recyclerview-layout

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

在此处输入图片说明

我能够通过遵循此处建议的内容来显示下一张和上一张卡片的一部分,但这只会将所有卡片统一居中: 如何显示下一张/上一张卡片的一部分 RecyclerView

我尝试覆盖 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;
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

房车设置

 SnapHelper snapHelper = new PagerSnapHelper();
        RecyclerView rv = getBinding().rv;
        rv.setOnFlingListener(null);
        snapHelper.attachToRecyclerView(rv);
Run Code Online (Sandbox Code Playgroud)

Che*_*amp 5

PagerSnapHelper将包括装饰在内的RecyclerView项目居中,因此,除非装饰宽度平衡,否则它们不会始终居中。这可能就是你所看到的。

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

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);
                }
            }
        };
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明

如果您已经使装饰效果满意,您可以calculateDistanceToFinalSnap()PagerSnapHelper 中覆盖以将除第一个和最后一个视图之外的所有视图居中,如下所示。请参阅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};  
    }  
};
Run Code Online (Sandbox Code Playgroud)

无论哪种方式都会起作用。