Nik*_*nko 5 android android-custom-view android-canvas android-view android-recyclerview
我有一个RecyclerViewwith GridLayoutManager,其中包含各种ViewTypes(以及SpanSizes )的项目。我需要为所有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;
}
}
Run Code Online (Sandbox Code Playgroud)
一切正常,除了图像下方没有绘制其他项目。我想这是因为我在实际绘制任何项目之前剪辑了画布。那么我应该如何剪辑画布以保存圆角并显示所有其他项目?
我终于找到了解决方案,而且非常简单。我需要做的就是提供以下的其他部分canvas:
正如你所看到的,顶部、左侧和右侧的点与第一个矩形相同,因此我们只需要找到底部:
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);
}
Run Code Online (Sandbox Code Playgroud)
创建一个新的矩形:
final RectF otherItemsRect = new RectF(rectToClip);
otherItemsRect.top = otherItemsRect.bottom;
otherItemsRect.bottom = maxBottom;
Run Code Online (Sandbox Code Playgroud)
将其包含到Path然后剪辑中:
final Path path = new Path();
path.addRoundRect(rectToClip, radius, radius, Path.Direction.CW);
path.addRect(otherItemsRect, Path.Direction.CW);
canvas.clipPath(path);
Run Code Online (Sandbox Code Playgroud)
就是这样。现在我们拥有所有带有圆角图像的项目
PS 为了简单起见,我在这里不提供优化的代码