如何仅为特定的 ViewType 设置 ItemDecoration?
How to set ItemDecoration only for certain ViewType?
我想为Header Type
画一个默认的ItemDecoration
到RecycleView
。但是每个 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);
}
}
}
});
我想为Header Type
画一个默认的ItemDecoration
到RecycleView
。但是每个 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);
}
}
}
});