ImageView剪裁为多边形

时间:2014-07-19 04:58:11

标签: android android-canvas android-custom-view

我想创建一个ImageView,将其内容剪辑到多边形内(在本例中为六边形)。我将视图的图层类型设置为软件,以便我可以使用canvas.clipPath()

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    setLayerType (LAYER_TYPE_SOFTWARE, null);
}

生成六边形的代码似乎工作正常:

Without clipping

这是计算顶点的代码:

@Override public void calculateVertices () {
    width = 2f * radius;
    side = 1.5f * radius;
    height = (float) Math.sqrt (3f) * radius;

    vertices = new Point[6];

    int minX = Integer.MAX_VALUE;
    int minY = Integer.MAX_VALUE;
    int maxX = Integer.MIN_VALUE;
    int maxY = Integer.MIN_VALUE;

    final float[] p0 = new float[] {center.x - radius, center.y};

    final Matrix m = new Matrix ();
    final float r = getRotation ();

    for (int i = 0; i < vertices.length; i++) {
        final float ptRot = rotateBy (r, (float) i * 60f);
        final float[] point = new float[2];

        if (ptRot != 0f) {
            m.reset ();
            m.postRotate (ptRot, center.x, center.y);
            m.mapPoints (point, p0);
        } else {
            point[0] = p0[0];
            point[1] = p0[1];
        }

        if (point[0] < minX) {
            minX = Math.round (point[0]);
        } else if (point[0] > maxX) {
            maxX = Math.round (point[0]);
        }

        if (point[1] < minY) {
            minY = Math.round (point[1]);
        } else if (point[1] > maxY) {
            maxY = Math.round (point[1]);
        }

        vertices[i] = fromFloat (point);
    }

    path.reset ();
    clipPath.reset ();

    path.moveTo (vertices[0].x, vertices[0].y);
    clipPath.moveTo (vertices[0].x, vertices[0].y);

    for (int i = 1; i < vertices.length; i++) {
        path.lineTo (vertices[i].x, vertices[i].y);
        clipPath.lineTo (vertices[i].x, vertices[i].y);
    }

    path.lineTo (vertices[0].x, vertices[0].y);
    clipPath.lineTo (vertices[0].x, vertices[0].y);
    path.close ();
    clipPath.close ();
    enclosure.set (minX, minY, maxX, maxY);
}

如上所示,同样的方法生成边界矩形以及定义多边形的路径和多边形的剪切路径。

在此视图的构造函数中,pathclipPath被定义为

path = new Path ();
clipPath = new Path ();
clipPath.setFillType (Path.FillType.INVERSE_EVEN_ODD);

视图的onDraw方法被覆盖:

@Override protected void onDraw (final Canvas canvas) {
    final int count = canvas.save ();
    canvas.clipPath (hexagon.getClipPath ());
    super.onDraw (canvas);
    hexagon.draw (canvas, selectBackgroundPaint ());
    canvas.restoreToCount (count);
}

只要我使用canvas.clipPath (hexagon.getClipPath ());启用该行,视图就会显示:

Clipping enabled

4个裁剪点中有2个甚至不在我的路上!!

我在这里做错了什么?有没有更好的方法呢?

最终,我希望多边形之外的所有内容都只是透明的。总是。包括选择突出显示。

我很感激帮助。我无法发布太多代码(公司IP等),但如果您需要更多详细信息,请通知我,我会更新。

2 个答案:

答案 0 :(得分:1)

我已经完全回答了你想要的一个问题。 @SceLus 还有answer被接受的是如此优秀和赏金的赢家,所以你可以从中获得帮助,因为链接可能会改变,所以我复制粘贴那个代码

<强> HexagonMaskView.java

public class HexagonMaskView extends View {
private Path hexagonPath;
private Path hexagonBorderPath;
private float radius;
private float width, height;
private int maskColor;

public HexagonMaskView(Context context) {
    super(context);
    init();
}

public HexagonMaskView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public HexagonMaskView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}

private void init() {
    hexagonPath = new Path();
    hexagonBorderPath = new Path();
    maskColor = 0xFF01FF77;
}

public void setRadius(float r) {
    this.radius = r;
    calculatePath();
}

public void setMaskColor(int color) {
    this.maskColor = color;
    invalidate();
}

private void calculatePath() {
    float triangleHeight = (float) (Math.sqrt(3) * radius / 2);
    float centerX = width / 2;
    float centerY = height / 2;
    hexagonPath.moveTo(centerX, centerY + radius);
    hexagonPath.lineTo(centerX - triangleHeight, centerY + radius / 2);
    hexagonPath.lineTo(centerX - triangleHeight, centerY - radius / 2);
    hexagonPath.lineTo(centerX, centerY - radius);
    hexagonPath.lineTo(centerX + triangleHeight, centerY - radius / 2);
    hexagonPath.lineTo(centerX + triangleHeight, centerY + radius / 2);
    hexagonPath.moveTo(centerX, centerY + radius);

    float radiusBorder = radius - 5;
    float triangleBorderHeight = (float) (Math.sqrt(3) * radiusBorder / 2);
    hexagonBorderPath.moveTo(centerX, centerY + radiusBorder);
    hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY
            + radiusBorder / 2);
    hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY
            - radiusBorder / 2);
    hexagonBorderPath.lineTo(centerX, centerY - radiusBorder);
    hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY
            - radiusBorder / 2);
    hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY
            + radiusBorder / 2);
    hexagonBorderPath.moveTo(centerX, centerY + radiusBorder);
    invalidate();
}

@Override
public void onDraw(Canvas c) {
    super.onDraw(c);
    c.clipPath(hexagonBorderPath, Region.Op.DIFFERENCE);
    c.drawColor(Color.WHITE);
    c.save();
    c.clipPath(hexagonPath, Region.Op.DIFFERENCE);
    c.drawColor(maskColor);
    c.save();
}

// getting the view size and default radius
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    width = MeasureSpec.getSize(widthMeasureSpec);
    height = MeasureSpec.getSize(heightMeasureSpec);
    radius = height / 2 - 10;
    calculatePath();
}
}

enter image description here

答案 1 :(得分:0)

这里的兄弟是解决方案..

https://github.com/MostafaGazar/CustomShapeImageView有关详细信息https://coderwall.com/p/hmzf4w

使用此库,您将在此库中找到圆形形状,也易于使用。

你也可以像云一样为这个库制作自定义形状。这个库支持SVG文件格式,他们制作了圆角Imageview的SVG文件。

只要使用并告诉我是否有任何问题