圆角ItemDecoration

Round corners ItemDecoration

我有一个 RecyclerViewGridLayoutManager,其中包含具有各种 ViewTypes(以及 SpanSize 的项目)。我需要为所有 R.layout.item_image 类型圆角,如下图

所以我创建了一个 ItemDecoration 来计算将在其上绘制这些项目的 Rect。然后将 Canvas 剪辑到此 Rect (使用 Path 圆角):

public class RoundCornersDecoration extends RecyclerView.ItemDecoration {
    private final float radius;
    private final RectF defaultRectToClip;

    public RoundCornersDecoration(float radius) {
        this.radius = radius;
        defaultRectToClip = new RectF(Float.MAX_VALUE, Float.MAX_VALUE, 0, 0);
    }

    @Override
    public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
        final RectF rectToClip = getRectToClip(parent);

        // has no items with ViewType == `R.layout.item_image`
        if (rectToClip.equals(defaultRectToClip)) {
            return;
        }

        final Path path = new Path();
        path.addRoundRect(rectToClip, radius, radius, Path.Direction.CW);
        canvas.clipPath(path);
    }

    private RectF getRectToClip(RecyclerView parent) {
        final RectF rectToClip = new RectF(defaultRectToClip);
        final Rect childRect = new Rect();
        for (int i = 0; i < parent.getChildCount(); i++) {
            if (!isImage(parent, i)) {
                continue;
            }

            final View child = parent.getChildAt(i);
            parent.getDecoratedBoundsWithMargins(child, childRect);

            rectToClip.left = Math.min(rectToClip.left, childRect.left);
            rectToClip.top = Math.min(rectToClip.top, childRect.top);
            rectToClip.right = Math.max(rectToClip.right, childRect.right);
            rectToClip.bottom = Math.max(rectToClip.bottom, childRect.bottom);
        }
        return rectToClip;
    }

    private boolean isImage(RecyclerView parent, int viewPosition) {
        final RecyclerView.Adapter adapter = parent.getAdapter();
        final int viewType = adapter.getItemViewType(viewPosition);
        return viewType == R.layout.item_image;
    }
}

一切正常,除了图像下方没有绘制其他项目。 我想那是因为我在 canvas 之前 实际绘制了任何项目。那么我应该如何剪辑 canvas 以保存圆角并显示所有其他项目?

我终于找到了解决办法,而且很简单。我需要做的就是提供 canvas 的另一部分 :

可以看到topleftright点是一样的第一个 rect 所以我们只需要找到 bottom:

    int maxBottom = 0;
    final Rect childRect = new Rect();
    for (int i = 0; i < parent.getChildCount(); i++) {
        final View child = parent.getChildAt(i);
        parent.getDecoratedBoundsWithMargins(child, childRect);
        maxBottom = Math.max(maxBottom, childRect.bottom);
    }

新建一个矩形:

    final RectF otherItemsRect = new RectF(rectToClip);
    otherItemsRect.top = otherItemsRect.bottom;
    otherItemsRect.bottom = maxBottom;

将其包含在 Path 中,然后剪辑:

    final Path path = new Path();
    path.addRoundRect(rectToClip, radius, radius, Path.Direction.CW);
    path.addRect(otherItemsRect, Path.Direction.CW);
    canvas.clipPath(path);

就是这样。现在我们有了所有带圆角的图像项目

P.S。为了简单起见,我在这里不提供优化代码