虽然您要求的是基于XML的解决方案,但我很有兴趣构建一个自定义的
Drawable
来解决您的问题。它基本上只是使用自定义路径绘制两个形状并在它们周围添加边框。如果您为颜色添加setter或将其作为构造函数参数,则可以获得所需的灵活性,以适应应用程序主题更改。如果XML是您选择的方式,请随意忽略此内容,我很乐意构建它。 :)
它看起来像这样:
![Screenshot of custom drawable](https://istack.dev59.com/bOUBK.webp)
public class CustomDrawable extends Drawable {
private final int mBorderWidth;
private final int mCornerRadius;
private final Paint mBorderPaint = new Paint();
private final Paint mTopLeftShapePaint = new Paint();
private final Paint mBottomRightShapePaint = new Paint();
private final RectF mBorderRect = new RectF();
private final Path mTopLeftShapePath = new Path();
private final Path mBottomRightShapePath = new Path();
public CustomDrawable() {
mBorderWidth = 8;
mCornerRadius = 64;
mTopLeftShapePaint.setColor(Color.parseColor("#00a2e8"));
mTopLeftShapePaint.setStyle(Paint.Style.FILL);
mTopLeftShapePaint.setAntiAlias(true);
mBottomRightShapePaint.setColor(Color.parseColor("#3f48cc"));
mBottomRightShapePaint.setStyle(Paint.Style.FILL);
mBottomRightShapePaint.setAntiAlias(true);
mBorderPaint.setColor(Color.parseColor("#3f48cc"));
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setStrokeWidth(mBorderWidth);
mBorderPaint.setAntiAlias(true);
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mBorderRect.set(bounds);
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
calculatePaths();
}
private void calculatePaths() {
RectF topLeftCorner = new RectF(mBorderRect.left, mBorderRect.top, mBorderRect.left + 2 * mCornerRadius, mBorderRect.top + 2 * mCornerRadius);
RectF topRightCorner = new RectF(mBorderRect.right - 2 * mCornerRadius, mBorderRect.top, mBorderRect.right, mBorderRect.top + 2 * mCornerRadius);
RectF bottomLeftCorner = new RectF(mBorderRect.left, mBorderRect.bottom - 2 * mCornerRadius, mBorderRect.left + 2 * mCornerRadius, mBorderRect.bottom);
RectF bottomRightCorner = new RectF(mBorderRect.right - 2 * mCornerRadius, mBorderRect.bottom - 2 * mCornerRadius, mBorderRect.right, mBorderRect.bottom);
PointF topRightCornerIntersection = calculateCircleCoordinate(topRightCorner.centerX(), topRightCorner.centerY(), 315);
PointF bottomLeftCornerIntersection = calculateCircleCoordinate(bottomLeftCorner.centerX(), bottomLeftCorner.centerY(), 135);
mTopLeftShapePath.reset();
mTopLeftShapePath.moveTo(topLeftCorner.left, topLeftCorner.centerY());
mTopLeftShapePath.lineTo(bottomLeftCorner.left, bottomLeftCorner.centerY());
mTopLeftShapePath.arcTo(bottomLeftCorner, -180, -45, false);
mTopLeftShapePath.lineTo(topRightCornerIntersection.x, topRightCornerIntersection.y);
mTopLeftShapePath.arcTo(topRightCorner, -45, -45, false);
mTopLeftShapePath.lineTo(topLeftCorner.centerX(), topLeftCorner.top);
mTopLeftShapePath.arcTo(topLeftCorner, -90, -90, false);
mBottomRightShapePath.reset();
mBottomRightShapePath.moveTo(bottomLeftCorner.centerX(), bottomLeftCorner.bottom);
mBottomRightShapePath.lineTo(bottomRightCorner.centerX(), bottomRightCorner.bottom);
mBottomRightShapePath.arcTo(bottomRightCorner, 90, -90, false);
mBottomRightShapePath.lineTo(topRightCorner.right, topRightCorner.centerY());
mBottomRightShapePath.arcTo(topRightCorner, 0, -45, false);
mBottomRightShapePath.lineTo(bottomLeftCornerIntersection.x, bottomLeftCornerIntersection.y);
mBottomRightShapePath.arcTo(bottomLeftCorner, 135, -45, false);
}
private PointF calculateCircleCoordinate(float centerX, float centerY, double angdeg) {
double angle = Math.toRadians(angdeg);
double x = centerX + mCornerRadius * Math.cos(angle);
double y = centerY + mCornerRadius * Math.sin(angle);
return new PointF((float) x, (float) y);
}
@Override
public void draw(@NonNull Canvas canvas) {
canvas.drawPath(mTopLeftShapePath, mTopLeftShapePaint);
canvas.drawPath(mBottomRightShapePath, mBottomRightShapePaint);
canvas.drawRoundRect(mBorderRect, mCornerRadius, mCornerRadius, mBorderPaint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.UNKNOWN;
}
}
免责声明:此快速草稿不包括边缘情况,例如给定视图边界太大的角半径。