【问题标题】:RecyclerView/SnapHelper - How to set variable position of the cards so that they peek differently based on positionRecyclerView/SnapHelper - 如何设置卡片的可变位置,以便它们根据位置进行不同的查看
【发布时间】:2019-06-01 07:44:55
【问题描述】:

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

按照这里的建议,我能够实现显示下一张和上一张卡片的部分内容,但这只会将所有卡片统一居中: 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;
      }
    }
  }

房车设置

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

【问题讨论】:

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


    【解决方案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);
                    }
                }
            };
    

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

    如果您的装饰效果已经令人满意,您可以在 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};  
        }  
    };
    

    任何一种方式都可以。

    【讨论】:

    • 我实际上并不是在寻找平衡的左右装饰使用分隔线。我实际上正在寻找如何根据位置为项目设置可变边距。但我看到了这个想法,让我看看这是否可行。
    • @RamPrasadBismil 看看我在答案中发布的视频。如果不是你所描述的,有什么不同?
    • 您能否再解释一下您的解决方案。我觉得这是在改变不同位置的分隔线宽度,但这需要保持不变,第二张卡片需要向左移动更多。因为使用当前的解决方案,我无法看到我想要的第二张卡片。
    • @RamPrasadBismil 当然。第一张卡片与 RecyclerView 的左侧对齐(实际上它的左侧装饰对齐)。第二个视图紧靠第一个视图的右侧装饰。这填充了 RecyclerView 的宽度。如果第二个视图是向左滑动所以它显示更多什么会放弃空间? (我们也可以去掉 1/2 宽度的装饰,用稍微不同的逻辑替换成全宽度的装饰。)
    • 所以我更新了图像,让我们说它有点棘手。所以第一张卡之前的填充是 16dp 和最后一张卡之后的相同。卡片之间的边距是恒定的 12dp。现在第二张卡片应该显示 32dp 和倒数第二张卡片相同,其余卡片都显示 16dp 并且中间的卡片居中。现在对于这种情况,我们需要将第二张和第二张卡片分别向左和向右移动,并且我们需要确保它们在滚动时居中。 @Cheticamp
    猜你喜欢
    • 2015-09-29
    • 2017-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    相关资源
    最近更新 更多