我想创建一个 ImageView
将其内容剪辑到多边形(在本例中为六边形)内。我将 View 的图层类型设置为软件,这样我就可以使用 canvas.clipPath()
:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType (LAYER_TYPE_SOFTWARE, null);
}
生成六边形的代码似乎工作正常:
这是计算顶点的代码:
@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);
}
如上所示,同样的方法生成边界矩形以及定义多边形的路径和多边形的裁剪路径。
在这个 View 的构造函数中,path
和 clipPath
是这样定义的
path = new Path ();
clipPath = new Path ();
clipPath.setFillType (Path.FillType.INVERSE_EVEN_ODD);
View 的 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 ());
启用该行, View 就会显示如下:
4 个剪切点中的 2 个甚至不在我的路径上!!
我在这里做错了什么?有更好的方法吗?
最终我希望多边形之外的所有东西都只是透明的。总是。包括选择突出显示。
感谢您的帮助。我不能发布太多代码(公司 IP 等),但如果您需要更多详细信息,请告诉我,我会更新。
最佳答案
我已经回答了一个你想要的问题。 @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();
}
}
关于android - ImageView 裁剪为多边形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24836921/