I want to create an ImageView
that clips its content to inside a polygon (in this case a hexagon). I'm setting the view's layer type to software so I can use canvas.clipPath()
:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType (LAYER_TYPE_SOFTWARE, null);
}
The code that generates the hexagon seems to work fine:
Here's the code that calculates the vertices:
@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);
}
As you can see above, the same method generates the bounding rectangle as well as the path that defines the polygon and the clipping path of the polygon.
In the constructor of this view, path
and clipPath
are defined as such
path = new Path ();
clipPath = new Path ();
clipPath.setFillType (Path.FillType.INVERSE_EVEN_ODD);
The onDraw
method of the view is overridden as such:
@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);
}
As soon as I enable the line with canvas.clipPath (hexagon.getClipPath ());
The view displays as such:
2 of the 4 clipping points aren't even on my path!!
What am I doing wrong here? Is there a better way of doing this?
Ultimately I want everything outside of the polygon to be only transparent. Always. Including the selection highlighting.
I appreciate the help. I can't publish too much of the code (Company IP, etc), but if you need more details let me know and I will update.