如何仅为特定的 ViewType 设置 ItemDecoration?

How to set ItemDecoration only for certain ViewType?

我想为Header Type画一个默认的ItemDecorationRecycleView。但是每个 ViewType.

都会显示 divider

自定义装饰:

class DividerDecoration(context: Context, orientation: Int)
    : DividerItemDecoration(context, orientation){

    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
        val position = parent.getChildAdapterPosition(view)
        val viewType = parent.adapter!!.getItemViewType(position)
        if (viewType == ITEM_VIEW_TYPE_HEADER){
            super.getItemOffsets(outRect, view, parent, state)
        } else {
            outRect.setEmpty()
        }
    }
}

设置:

val itemDecoration = DividerDecoration(binding.recyclerView.context, 
                                       DividerItemDecoration.VERTICAL)
binding.recyclerView.addItemDecoration(itemDecoration)

对于为什么会发生这种情况有什么建议吗?

更新

上面的代码是有效的。但是有一个错误。启动应用程序后,分隔符出现在所有元素中,然后仅出现在正确的元素中。为什么会这样?

覆盖你的物品装饰 onDraw 并且只在物品出现时执行抽奖 被装饰在你认为还可以的位置。

我不会创建另一个示例,我只会向您指出一个工作示例,该示例不完全您想要的,但肯定会为您指明正确的方向: 如何有选择地绘制分隔线。

在我看来,尝试从 Decoration 实现中执行此操作很麻烦。现在装饰必须知道数据集,所以你有一个视图直接访问适配器来访问数据。您正在确定多个不同 class 中哪些位置是 header。意大利面和重复。

理想情况下,适配器 class 将处理 Decorations 的应用程序,因此您可以有选择地执行它,但由于它没有,我认为目前最好的方法是将header 布局中的分隔线,在 onBindView 中,如果位置为 0(最上面的 header),您可以关闭它的可见性。

问题

我的错误在于使用 ItemDecoration 来为不同的 ViewType 设置自定义分隔符。我已经形成了一个明确的信念,即这样的自定义分隔线应该只做 ItemDecoration.

根据我的问题 image gif,它给出了一个错误。我找不到解决办法。 Whosebug 上的其他帖子正在向 override 提供方法:getItemOffsets()onDraw()。我试图实施至少四种情况。他们都以绘图错误告终(类似于我问题中的 gif)。

搜索

我不知道是什么原因导致这些绘图错误。感谢 的回答和评论。我更改了搜索关键字并找到了简单的解决方案。

顺便说一下,我的应用程序设计采用了Google 中应用程序设计的一些特征。我反编译了其中一个应用程序的 apk。并找到了与解决方案中描述的完全相同的分隔符的资源。对此,我可以考虑这个决定 best practices from Google.

解决方案

我有两个ViewType。每个都有自己的布局。解决方案是在页眉布局中添加一个分隔符。

因为 ViewTypeHeader 仅在存在嵌套元素时出现,在我的例子中,我不需要为最后一个或第一个元素添加条件 Visible

layout\ViewTypeHeader.xml

<LinearLayout ...>

    <TextView ... />

    <!-- This -->
    <View style="@style/DividerStyle" />

</LinearLayout>

values/styles.xml

<style name="DividerStyle">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">@dimen/dividerHeight</item>
    <item name="android:background">@android:color/black</item>
</style>

结论

如果有多个 ViewType - 忘记 ItemDecoration。节省很多时间。

以下是根据视图类型或位置显示或隐藏分隔线的方法。将其包含在您的 activity/fragment.

recyclerView.addItemDecoration(new DividerItemDecoration(this, linearLayoutManager.getOrientation()) {
            @Override
            public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
                Drawable d = getDrawable();
                for (int i = 0; i < parent.getChildCount(); i++) {
                    View view = parent.getChildAt(i);
                    int position = parent.getChildAdapterPosition(view);
                    int viewType = parent.getAdapter().getItemViewType(position);
                    
                    // Draw divider only for view type 2 (can also put position here to remove for certain positions)
                    if(viewType == 2) {
                        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
                        int top = view.getBottom() + params.bottomMargin;
                        int bottom = top + d.getIntrinsicHeight();
                        d.setBounds(0, top, parent.getRight(), bottom);
                        d.draw(c);
                    }
                }
            }
        });