创建自定义凸形路径Android

4

我希望为我的框架布局设置自定义形状(每个矩形角的半径不同),这样框架布局中的视图将被剪裁到形状的边界。

    ViewOutlineProvider provider = new ViewOutlineProvider() {
        @Override
        public void getOutline(View view, Outline outline) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                configurePath(getWidth(), getHeight());
                outline.setConvexPath(borderPath);
            }
        }
    };

    setOutlineProvider(provider);
    setClipToOutline(true);

configurePath() 的代码如下:

private void configurePath (int width, int height) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        return;
    }

    borderPath.rewind();

    float minSize = Math.min(width, height);
    float maxRadiusWidth = 2 * Math.max(Math.max(topLeftRadius, topRightRadius),
            Math.max(bottomLeftRadius, bottomRightRadius));

    if (minSize < maxRadiusWidth) {
        borderPath.addRect(0, 0, width, height, Path.Direction.CCW);
        return;
    }

    // Top left circle
    oval.set(0, 0, 2 * topLeftRadius, 2 * topLeftRadius);
    borderPath.moveTo(0, topLeftRadius);
    borderPath.arcTo(oval, 180, -90);

    borderPath.rLineTo(width - topLeftRadius - topRightRadius, 0);

    // Top right circle
    oval.set(width - 2 * topRightRadius, 0, width, 2 * topRightRadius);
    borderPath.arcTo(oval, 90, -90);

    borderPath.rLineTo(0, height - topRightRadius - bottomRightRadius);

    // Bottom right circle
    oval.set(width - 2 * bottomRightRadius, height - 2 * bottomRightRadius, width, height);
    borderPath.arcTo(oval, 0, -90);

    borderPath.rLineTo(-width + bottomRightRadius + bottomLeftRadius, 0);

    // Bottom left circle
    oval.set(0, height - 2 * bottomLeftRadius, 2 * bottomLeftRadius, height);
    borderPath.arcTo(oval, -90, -90);

    borderPath.rLineTo(0, -height + bottomLeftRadius + topLeftRadius);
}

当我运行它时,我得到了“java.lang.IllegalArgumentException:路径必须是凸的”,我无法进入“native_isConvex()”并查看它如何确定路径是否是凸的。
那么什么是凸路径?为什么在“configurePath()”中的路径不是凸的? 如何创建自定义凸路径?谢谢。

面临相同的问题。目前,我知道当我仅使用lineTo方法时,isConvex可以返回true。使用quadToarcTo会导致isConvex返回false。也许这可以是一些提示... - pawel-schmidt
@pxsxYeah,“arcTo”正是我认为导致问题的原因。但是我必须使用它,因为我打算为视图组创建自定义形状。无论如何,我已经通过clipPath解决了自定义形状问题。 - zek_w
2个回答

1
我自己解决了这个问题。路径不是凸的,因为我没有正确地绘制路径。实现我想要的多角半径效果的正确路径应该是:
    // Top left circle
    oval.set(0, 0, 2 * topLeftRadius, 2 * topLeftRadius);
    borderPath.moveTo(0, topLeftRadius);
    borderPath.arcTo(oval, -180, 90);

    borderPath.rLineTo(width - topLeftRadius - topRightRadius, 0);

    // Top right circle
    oval.set(width - 2 * topRightRadius, 0, width, 2 * topRightRadius);
    borderPath.arcTo(oval, -90, 90);

    borderPath.rLineTo(0, height - topRightRadius - bottomRightRadius);

    // Bottom right circle
    oval.set(width - 2 * bottomRightRadius, height - 2 * bottomRightRadius, width, height);
    borderPath.arcTo(oval, 0, 90);

    borderPath.rLineTo(-width + bottomRightRadius + bottomLeftRadius, 0);

    // Bottom left circle
    oval.set(0, height - 2 * bottomLeftRadius, 2 * bottomLeftRadius, height);
    borderPath.arcTo(oval, 90, 90);

    borderPath.rLineTo(0, -height + bottomLeftRadius + topLeftRadius);

更新:虽然路径现在是正确的,但仍不是凸路径,似乎定制路径不会被视为凸路径。

0
很高兴你已经让它工作了,但是有内置的工具可以做到这一点。
最简单的方法是在可绘制的XML文件中:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners
        android:bottomLeftRadius="8dp"
        android:topLeftRadius="8dp"
        android:topRightRadius="8dp"
        android:bottomRightRadius="0dp" />

    <solid android:color="#fff" />

</shape>

在编程中,您可以使用RoundRectShape类。这也是从上面的xml文件中膨胀出来的。
在构造函数中,您需要传递外部角半径、线条厚度和内部角半径。您还可以查看源代码以了解如何创建路径(提示:path.addRoundRect())。


1
谢谢你让我知道 addRoundRect(RectF rect, float[] radii, Direction dir)。但是根据 Outline 的源代码:public boolean canClip() { return mMode != MODE_CONVEX_PATH; },轮廓不支持剪裁自定义形状。 - zek_w

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接