圆角ItemDecoration
Round corners ItemDecoration
我有一个 RecyclerView
和 GridLayoutManager
,其中包含具有各种 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
的另一部分 :
可以看到top、left和right点是一样的第一个 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。为了简单起见,我在这里不提供优化代码
我有一个 RecyclerView
和 GridLayoutManager
,其中包含具有各种 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
的另一部分 :
可以看到top、left和right点是一样的第一个 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。为了简单起见,我在这里不提供优化代码