RecyclerView 中最后一个子项的边距/填充

Posted

技术标签:

【中文标题】RecyclerView 中最后一个子项的边距/填充【英文标题】:Margin/padding in last Child in RecyclerView 【发布时间】:2016-02-18 16:14:37 【问题描述】:

我正在尝试在最后一行添加 Padding/Margin Bottom 并在第一行添加 Padding/Margin Top。我不能在项目 xml 中这样做,因为它会影响我所有的孩子。

我的 RecyclerView 适配器中有标题和子项,因此我无法使用

   android:padding="4dp"
   android:clipToPadding="false"

我需要在每个标题的最后第一行单独使用它

【问题讨论】:

这样使用: 您可以在 onBindViewHolder 中更改填充和边距,然后在视图持有者上调用 setIsRecyclable(false) 请将@Subin Sebastian 的答案标记为正确 【参考方案1】:

使用ItemDecoration:

private class SpacesItemDecoration extends RecyclerView.ItemDecoration 
    private int space;

    public SpacesItemDecoration(int space) 
        this.space = space;
    

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) 
        int position = parent.getChildAdapterPosition(view);
        boolean isLast = position == state.getItemCount()-1;
        if(isLast)
            outRect.bottom = space;
            outRect.top = 0; //don't forget about recycling...
        
        if(position == 0)
            outRect.top = space;
            // don't recycle bottom if first item is also last
            // should keep bottom padding set above
            if(!isLast)
                outRect.bottom = 0;
        
    

//8dp as px
int space = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,
            getResources().getDisplayMetrics()); // calculated
//int space = getResources().getDimensionPixelSize(
//    R.dimen.list_item_padding_vertical); // from resources
recyclerView.addItemDecoration(new SpacesItemDecoration(space));

【讨论】:

嘿,RecyclerView.ItemDecoration 似乎不再获取资源类,我只是将它作为参数添加到构造函数中。 谷歌解决方案!支持反向布局:gist.github.com/Miha-x64/4e8754e72a1e65e3ca742744ea501f16 这个答案必须被赞成!尽管 Subin Sebastian 的回答效果很好,但是 ItemDecoration 的空间并不相等。 但在插入删除项目后,它不会重绘所有项目的偏移量 可能是真的,因为notifyItemInserted/Removed 将只绘制一个项目/删除项目并清理它View 使所有其他孩子保持不变。例如当某个项目在列表中的第一个(使用顶部填充绘制)并且我们将新的添加到顶部时,之前的第一个当前第二个项目仍将被填充在顶部......简单的解决方法是调用notifyDataSetChanged(强制重绘所有...),更复杂的需要一些逻辑来识别位于第一个和/或最后一个位置的项目,移动然后调用notifyItemChanged(newPositionOfOldFirstAndOrLastItem)【参考方案2】:

您可以只在 RecyclerView 的顶部和底部添加内边距,并将 clipToPadding 属性设置为 false,而不是为顶部和底部项目添加内边距。

<android.support.v7.widget.RecyclerView
    android:layout_
    android:layout_
    android:clipToPadding="false"
    android:paddingTop="8dp"
    android:paddingBottom="8dp" />

【讨论】:

这是一个简单的解决方案,但我的 RecyclerView 中有标题和子项,所以我不能使用它 @RedEagle 试试看你是否得到了想要的效果,但我确信它有效。 这个方案比物品装饰方案要好。当我使用 ListAdapter 并提交不同的列表时,如果上一个列表的最后一项没有更改其位置但在其后添加了新项,则前者将保留其底部填充,即使它不是列表中的最后一项更多。【参考方案3】:

这个问题更容易解决。您可以对RecylerView 本身应用必要的填充并将clipToPadding 设置为false,否则,填充将切断您的滚动区域。这是一个例子

<android.support.v7.widget.RecyclerView
    android:padding="4dp"
    android:clipToPadding="false"
    android:layout_
    android:layout_ />

看到填充将在包括顶部和底部在内的所有侧面添加 4dp。然后 clipToPadding 参数确保您的子项目没有被切断。现在,为您的子项目添加4dp 填充到所有侧面,您就可以开始了。总体而言,您在项目的侧面和项目之间获得 8dp 的内边距。

【讨论】:

是的,我通常是这样做的,但我的 RecyclerView 由标题组成,每个标题都有自己的孩子,这就是为什么我需要以编程方式将其设置为每个标题的最后一行和第一行 不确定我是否理解。这与 RecyclerView 中的标题有什么关系?您是否希望标题没有填充?即使是这种情况,您也可以使用相同的解决方案摆脱左右填充。 我有标题,每个标题都有非特定数量的子元素,所以我想在每个标题的最后一个子元素中添加顶部填充/边距以及第一个子元素和底部填充/边距。 我唯一的想法是在标题布局中设置顶部和底部边距,但我想知道是否有更聪明的方法来实现它 是的! clipToPadding 是我一直在寻找的。​​span> 【参考方案4】:

由于某种原因,旧的 clipToPadding=false 解决方案不适合我。所以我添加了一个ItemDecoration

https://gist.github.com/kassim/582888fa5960791264fc92bc41fb6bcf

public class BottomPaddingDecoration extends RecyclerView.ItemDecoration 
    private final int bottomPadding;

    public BottomPaddingDecoration(int bottomPadding) 
        this.bottomPadding = bottomPadding;
    

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) 
        int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
        if (position == parent.getAdapter().getItemCount() - 1) 
            outRect.set(0, 0, 0, bottomPadding);
        
    

【讨论】:

【参考方案5】:
<android.support.v7.widget.RecyclerView
    android:id="@+id/rv_tpf"
    android:layout_
    android:layout_
    android:clipToPadding="false"
    android:paddingBottom="100dp" />

在您的回收站视图中添加 android:clipToPadding="false"android:paddingBottom="100dp"

【讨论】:

太棒了!太完美了【参考方案6】:

我在 kotlin 中使用它来为最后一个项目提供底部边距

override fun onBindViewHolder(holder: RecyclerView.ViewHolder(view), position: Int) 
    if (position == itemsList.lastIndex)
        val params = holder.itemView.layoutParams as FrameLayout.LayoutParams
        params.bottomMargin = 100
        holder.itemView.layoutParams = params
    else
        val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
        params.bottomMargin = 0
        holder.itemView.layoutParams = params
    
  //other codes ...

【讨论】:

【参考方案7】:

我已经修改了惊人的答案@snachmsm 答案,让你知道如何使用 正确的

public class SpacesItemDecoration extends DividerItemDecoration 
    private int space;

    public SpacesItemDecoration(Context clContext,int oriantation,int space) 
        super(clContext,oriantation);
        this.space = space;
    

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) 
        super.getItemOffsets(outRect,view,parent,state);
        int position = parent.getChildAdapterPosition(view);
        boolean isLast = position == state.getItemCount()-1;
        if(isLast)
            outRect.bottom = space;
            outRect.top = 0; //don't forget about recycling...
        
       /* if(position == 0)
            outRect.top = space;
            // don't recycle bottom if first item is also last
            // should keep bottom padding set above
            if(!isLast)
                outRect.bottom = 0;
        */
    

【讨论】:

【参考方案8】:

在您的回收站视图中添加 android:clipToPadding="false" 和 android:paddingBottom="65dp"。如果您在回收站视图单元上使用 fab 菜单按钮和操作。

<androidx.recyclerview.widget.RecyclerView
      android:id="@+id/dinner_recycler_view"
      android:layout_
      android:layout_
      android:clipToPadding="false"
      android:paddingBottom="65dp"/>

【讨论】:

【参考方案9】:

Java 等价于@Radesh 答案:

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) 
    if (position == itemsList.size() - 1) 
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) holder.itemView.getLayoutParams();
        params.bottomMargin = 100;
        holder.itemView.setLayoutParams(params);
     else 
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) holder.itemView.getLayoutParams();
        params.bottomMargin = 0;
        holder.itemView.setLayoutParams(params);
    

【讨论】:

它对我有用,谢谢【参考方案10】:

长话短说:

    int freeSpaceAtBottom = 100; // the bottom free space in pixels
    myRecyclerView.setClipToPadding(false);
    myRecyclerView.setPadding(0,0,0,freeSpaceAtBottom);

setClipToPadding 设置此列表视图是否将其子视图剪裁到其内边距并调整(但不剪裁)任何 EdgeEffect 到内边距区域(如果存在内边距)。 (1)

【讨论】:

以上是关于RecyclerView 中最后一个子项的边距/填充的主要内容,如果未能解决你的问题,请参考以下文章

在水平的RecyclerView中显示ImageView会在Android中的图像周围放置大的边距(?)

如何为最后一个元素为 RecyclerView 添加边距?

Flexbox 子项的折叠边距

CSS 删除第一个/最后一个元素的边距

StaggeredGridLayoutManager 重新排序项目而不考虑定义的边距

Flexbox 挑战:如何在整行中使用相同且均匀的边距进行换行