【问题标题】:How to set ItemDecoration only for certain ViewType?如何仅为某些 ViewType 设置 ItemDecoration?
【发布时间】:2019-12-14 02:49:24
【问题描述】:

我想为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)

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

更新

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

【问题讨论】:

  • 我不知道 Kotlin(我使用 Java),但我认为您不能只为第一项设置分隔符。
  • @GauravMall 我有header 为每个组按日期
  • 哦,好的,我明白了,如果我能提供帮助,我会看看!
  • 您是否尝试在getItemOffsets 内部使用parent.adapter.getItemViewType(parent.getChildAdapterPosition(view))?这可能有效 - 我自己还没有尝试过。
  • @GauravMall 你当然可以。

标签: android kotlin android-recyclerview item-decoration


【解决方案1】:

以下是根据视图类型或位置显示或隐藏分隔线的方法。将其包含在您的活动/片段中。

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

【讨论】:

    【解决方案2】:

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

    理想情况下,适配器类将处理装饰的应用程序,因此您可以有选择地执行此操作,但由于它没有,我认为暂时最好的方法是将分隔符放在您的标题布局中,并且在onBindView 中,如果位置为 0(最顶部的标题),您可以关闭其可见性。

    【讨论】:

    • 我不明白你的意思。我是初学者。
    • 您需要澄清哪一部分,第一段还是第二段?
    • 来自 Internet 的创建 ItemDecoration 的示例总是有一个实现,并在其他地方调用 add 方法。为什么我选择不同班级的头条? getItemOffsets 方法查看现有类型并决定他是否需要分隔符。据我了解,不建议在 ItemDecoration 中进行分隔。但如果这样做,如何在布局中画一条线?你看到更新帖子了吗?
    • 视图对象决定它应该与哪些其他视图组合只是糟糕的架构。使用 ItemDecorations 进行此操作的 Internet 示例是一种黑客攻击。 getItemOffsets 应该返回项目偏移量。返回无效偏移或将它们放置在仍会绘制它们但您看不到它们的位置是一种技巧。在我看来,由于我们可以简单地使用现有的适配器方法,因为它们旨在达到正确的结果,这是最干净的方法。
    • 您是否已经在适配器中为您的标题视图扩展布局?
    【解决方案3】:

    问题

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

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

    搜索

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

    顺便说一下,我的应用程序的设计采用了Google的应用程序设计的一些特性。我反编译了其中一个应用程序的 apk。并找到了完全按照解决方案中描述的方式制作分离器的资源。对此,我可以考虑best practices from Google这个决定。

    解决方案

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

    因为ViewTypeHeader 仅在存在嵌套元素时才会出现,所以在我的情况下,我不需要为最后一个或第一个元素添加带有Visible 的条件。

    布局\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。节省大量时间。

    【讨论】:

      【解决方案4】:

      覆盖您的物品装饰的onDraw 并且仅在物品 被装饰的位置你认为没问题。

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

      https://stackoverflow.com/a/46216274/2684

      【讨论】:

        猜你喜欢
        • 2016-05-02
        • 2012-12-15
        • 1970-01-01
        • 1970-01-01
        • 2019-05-21
        • 1970-01-01
        • 2020-12-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多