java recyclerview中基于viewtype的ItemDecoration

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35013383/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 23:38:51  来源:igfitidea点击:

ItemDecoration based on viewtype in recyclerview

javaandroidandroid-recyclerview

提问by user3531883

I have multiple view typesin my RecyclerViewand I want to add an ItemDecorationbased on the views type. Is there a way to do this?

我有多种视图类型,我RecyclerViewItemDecoration根据视图类型添加一个。有没有办法做到这一点?

This will add a decoration to every element:

这将为每个元素添加一个装饰:

recyclerView.addItemDecoration(decoration);

I saw this librarybut it supports only LinearLayoutManagervertical or horizontal, but I am using GrildLayoutManagerand I use drawables for dividers.

我看到了这个库,但它只支持LinearLayoutManager垂直或水平,但我正在使用GrildLayoutManager并且我使用 drawables 作为分隔线。

回答by David Medenjak

Yes, you can.

是的你可以。

If you draw the decoration yourself, you can distinguish between different view types in getItemOffsetsand onDrawby accessing the same method on the adapter like this:

如果你画的装饰自己,你可以在不同的视图类型区分getItemOffsets,并onDraw通过访问这样的适配器上的相同的方法:

// get the position
int position = parent.getChildAdapterPosition(view);
// get the view type
int viewType = parent.getAdapter().getItemViewType(position);

Using this, you can draw your decoration only for your selected views. By accessing getLeft()and getRight()that code supports GridLayoutas well as LinearLayout, to support horizontalalignment, the drawing just has to be done on the right side using the same approach.

使用它,您可以只为您选择的视图绘制装饰。通过访问getLeft()getRight()该代码支持GridLayout以及LinearLayout支持水平对齐,绘图只需使用相同的方法在右侧完成。

In the end, you would create a decoration like the following:

最后,您将创建一个如下所示的装饰:

public class DividerDecoration extends RecyclerView.ItemDecoration {

    private final Paint mPaint;
    private int mHeightDp;

    public DividerDecoration(Context context) {
        this(context, Color.argb((int) (255 * 0.2), 0, 0, 0), 1f);
    }

    public DividerDecoration(Context context, int color, float heightDp) {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(color);
        mHeightDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, heightDp, context.getResources().getDisplayMetrics());
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view);
        int viewType = parent.getAdapter().getItemViewType(position);
        if (viewType == MY_VIEW_TYPE) {
            outRect.set(0, 0, 0, mHeightDp);
        } else {
            outRect.setEmpty();
        }
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        for (int i = 0; i < parent.getChildCount(); i++) {
            View view = parent.getChildAt(i);
            int position = parent.getChildAdapterPosition(view);
            int viewType = parent.getAdapter().getItemViewType(position);
            if (viewType == MY_VIEW_TYPE) {
                c.drawRect(view.getLeft(), view.getBottom(), view.getRight(), view.getBottom() + mHeightDp, mPaint);
            }
        }
    }
}

There is a similar sample on GitHubwith a demo project, which will not draw before or after header views or at the very end.

GitHub 上有一个类似的示例,带有一个演示项目,不会在标题视图之前或之后或最后绘制。

回答by Reprator

Based on @David MedenJak answer, I had made my own Item Decorator for different view types as the answer lag in one condition as it draws decorator above section, if it comes after any normal row,

基于@David MedenJak 的回答,我为不同的视图类型制作了我自己的项目装饰器,因为当它在任何正常行之后绘制装饰器时,答案在一种情况下滞后,

    import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.ColorRes;
import android.support.annotation.DimenRes;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import java.util.Locale;

import mp.data.modal.MRecyclerListItem;

public class HeaderSimpleDividerDecoration extends RecyclerView.ItemDecoration {

    private int                 dividerHeight;
    private Paint               dividerPaint;

    public HeaderSimpleDividerDecoration(Context context, @DimenRes int divider_height, @ColorRes int color) {
        dividerPaint = new Paint();
        dividerPaint.setColor(getColor(context, color));
        dividerHeight = context.getResources().getDimensionPixelSize(divider_height);
    }

    private int getColor(Context context, @ColorRes int drawable) {
        return ContextCompat.getColor(context, drawable);
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        int position = parent.getChildAdapterPosition(view);
        if(-1 >= position)
            return;
        int viewType = parent.getAdapter().getItemViewType(position);

        if (MRecyclerListItem.TYPE_NORMAL == viewType) {
            // outRect.set(0, 0, 0, mHeightDp);
                outRect.bottom = dividerHeight;
        } else
            outRect.setEmpty();
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int childCount = parent.getChildCount() -1;
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();
        int top = parent.getPaddingTop();
        int bottom = parent.getHeight() - parent.getPaddingBottom();
        int itemCount = parent.getAdapter().getItemCount();

        for (int i = 0; i < childCount ; i++) {
            View view = parent.getChildAt(i);

            int position = parent.getChildAdapterPosition(view);
            int viewType = parent.getAdapter().getItemViewType(position);

            if (MRecyclerListItem.TYPE_NORMAL == viewType) {
                    int nextItem = position + 1;
                    if(nextItem < itemCount)
                    {
                        int nextViewType = parent.getAdapter().getItemViewType(nextItem);
                        if(MRecyclerListItem.TYPE_NORMAL != nextViewType)
                            continue;
                    }

                    float topDraw = view.getBottom();
                    float bottomDraw = view.getBottom() + dividerHeight;

                    c.drawRect(left, topDraw, right, bottomDraw, dividerPaint);
                }
            }

        }
    }

MRecyclerListItem.TYPE_NORMAL is your view type of normal row(other than header) call the above in following manager,

MRecyclerListItem.TYPE_NORMAL 是您的正常行(标题除外)的视图类型在以下管理器中调用上述内容,

 mRecyclerview.addItemDecoration(new HeaderSimpleDividerDecoration(context,
            2dp , R.color.view_profile_edit_view));

回答by Nicolas Duponchel

Hy people !

嗨人!

Example using 2 Drawableseparators for Horizontal ItemSeparatorbased on items view type :

基于项目视图类型Drawable为水平使用 2 个分隔符的示例ItemSeparator

override fun getItemOffsets(...) {
    parent.adapter?.let { adapter ->
        val childAdapterPosition = parent.getChildAdapterPosition(view)
            .let { if (it == RecyclerView.NO_POSITION) return else it }

        rect.right = when (adapter.getItemViewType(childAdapterPosition)) {
            YourAdapter.FIRST_ITEM_ID -> firstSeparator.intrinsicWidth
            YourAdapter.SECOND_ITEM_ID -> secondSeparator.intrinsicWidth
            else -> 0
        }
    }
}

override fun onDraw(...) {
    parent.adapter?.let { adapter ->
        parent.children
            .forEach { view ->
                val childAdapterPosition = parent.getChildAdapterPosition(view)
                    .let { if (it == RecyclerView.NO_POSITION) return else it }

                when (adapter.getItemViewType(childAdapterPosition)) {
                    CustomAdapter.FIRST_ITEM_ID -> firstSeparator.draw(...)
                    CustomAdapter.SECOND_ITEM_ID -> secondSeparator.draw(...)
                    else -> Unit
                }
            }
    }
}

private fun Drawable.draw(view: View, parent: RecyclerView, canvas: Canvas) = apply {
    val left = view.right
    val top = parent.paddingTop
    val right = left + intrinsicWidth
    val bottom = top + intrinsicHeight - parent.paddingBottom
    bounds = Rect(left, top, right, bottom)
    draw(canvas)
}

For more info on ItemSeparator, Hereis the article I wrote to explain how to build your own custom ItemDecoration.

有关更多信息ItemSeparator是我写的文章,用于解释如何构建您自己的自定义 ItemDecoration。