RecyclerView / SnapHelper-如何设置卡片的可变位置,以便根据位置不同地窥视

时间:2019-05-24 18:23:08

标签: android android-layout android-recyclerview recyclerview-layout

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

enter image description here

通过遵循此处的建议,我可以显示下一张和上一张纸牌的一部分,但这只会使所有纸牌统一居中: How to show part of next/previous card 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;
      }
    }
  }

RV设置

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

1 个答案:

答案 0 :(得分:1)

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

以下是显示带有灰色垂直分隔线的结果的视频。

enter image description here

如果您已经满意装饰的工作,则可以覆盖 PagerSnapHelper 中的calculateDistanceToFinalSnap(),以将除第一个和最后一个视图以外的所有视图居中,如下所示。参见calculatedistancetofinalsnap()。一旦 PageSnapHelper 标识了要捕捉到的目标视图,将调用calculatedistancetofinalsnap()以确定执行捕捉需要移动多少像素。在这里,我们移动的像素足够使 RecyclerView 中的视图居中(无装饰)。 PageSnapHelper 对第一项和最后一项执行正确的操作,因此我们仅对它们进行超级调用。

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

这两种方法都可以。