如何在安卓中绘制填充的多边形?
Android没有像Java那样方便的drawPolygon(x_array, y_array, numberofpoints)
操作。您必须逐点地创建一个Path
对象。例如,要为3D地牢墙壁制作填充的梯形形状,可以将所有点放入x和y数组,然后编写以下代码:
Paint wallpaint = new Paint();
wallpaint.setColor(Color.GRAY);
wallpaint.setStyle(Style.FILL);
Path wallpath = new Path();
wallpath.reset(); // only needed when reusing this path for a new build
wallpath.moveTo(x[0], y[0]); // used for first point
wallpath.lineTo(x[1], y[1]);
wallpath.lineTo(x[2], y[2]);
wallpath.lineTo(x[3], y[3]);
wallpath.lineTo(x[0], y[0]); // there is a setLastPoint action but i found it not to work as expected
canvas.drawPath(wallpath, wallpaint);
要为一些深度添加一个恒定的线性渐变,你可以按如下编码。注意,y [0] 被用两次以保持渐变水平:
wallPaint.reset(); // precaution when resusing Paint object, here shader replaces solid GRAY anyway
wallPaint.setShader(new LinearGradient(x[0], y[0], x[1], y[0], Color.GRAY, Color.DKGRAY,TileMode.CLAMP));
canvas.drawPath(wallpath, wallpaint);
你需要将画笔对象设置为FILL。
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
那么您可以画任何想要的东西,它们将被填充。
canvas.drawCircle(20, 20, 15, paint);
canvas.drawRectangle(60, 20, 15, paint);
对于更复杂的形状,您需要使用PATH对象。
我喜欢用三个步骤来完成...
第一步:创建一个尖锐的类 ;-)
/**
* Simple point
*/
private class Point {
public float x = 0;
public float y = 0;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
}
步骤2. 添加一个绘图方法/函数
/**
* Draw polygon
*
* @param canvas The canvas to draw on
* @param color Integer representing a fill color (see http://developer.android.com/reference/android/graphics/Color.html)
* @param points Polygon corner points
*/
private void drawPoly(Canvas canvas, int color, Point[] points) {
// line at minimum...
if (points.length < 2) {
return;
}
// paint
Paint polyPaint = new Paint();
polyPaint.setColor(color);
polyPaint.setStyle(Style.FILL);
// path
Path polyPath = new Path();
polyPath.moveTo(points[0].x, points[0].y);
int i, len;
len = points.length;
for (i = 0; i < len; i++) {
polyPath.lineTo(points[i].x, points[i].y);
}
polyPath.lineTo(points[0].x, points[0].y);
// draw
canvas.drawPath(polyPath, polyPaint);
}
第三步:画图
drawPoly(canvas, 0xFF5555ee,
new Point[]{
new Point(10, 10),
new Point(15, 10),
new Point(15, 20)
});
是的,你可能可以更有效率地做到这一点,但可能不会更易读 :-).
Point
和PointF
类,所以你不需要重新发明一个。其次,你真的应该避免在View.draw()方法中分配对象,而你提供的示例为了绘制一个单独的图形而进行了大量的对象分配。 - ralfoide使用自定义半径绘制x边形:
private void drawPolygon(Canvas mCanvas, float x, float y, float radius, float sides, float startAngle, boolean anticlockwise, Paint paint) {
if (sides < 3) { return; }
float a = ((float) Math.PI *2) / sides * (anticlockwise ? -1 : 1);
mCanvas.save();
mCanvas.translate(x, y);
mCanvas.rotate(startAngle);
Path path = new Path();
path.moveTo(radius, 0);
for(int i = 1; i < sides; i++) {
path.lineTo(radius * (float) Math.cos(a * i), radius * (float) Math.sin(a * i));
}
path.close();
mCanvas.drawPath(path, paint);
mCanvas.restore();
}
顺便说一下 - 我发现一旦你开始创建路径,路径内的任何moveTo命令都会导致形状未填充。
当你想到这一点时,它就有意义了,Android/Java会将形状留空,因为moveTo代表多边形中断。
然而,我看过一些像这样的教程如何在Android画布中绘制填充三角形?
其中每个lineTo后面都有一个moveTo。即使这可能会导致多边形不连续,但Android仍然认为moveTo代表多边形中断。
虽然这是一个老问题,但对于任何发现此问题的人都有一个技巧。如果您包含了所需多边形作为字形的字体,则可以使用drawText函数绘制多边形。
缺点是您必须事先知道需要哪些形状。好处是,如果您事先知道,可以包含一个漂亮的形状库。此代码假定您在项目的assets/fonts文件夹中有一个名为shapes的字体。
TypeFace shapesTypeFace = Typeface.createFromAsset(getAssets(), "fonts/shapes.ttf");
Paint stopSignPaint = new Paint();
stopSignPaint.setColor(Color.RED);
//set anti-aliasing so it looks nice
stopSignPaint.setAntiAlias(true);
stopSignPaint.setTextSize(200);
stopSignPaint.setTypeface(shapesTypeFace);
//will show up as a box or question mark since
//the current display font doesn't have this glyph.
//open the shapes font in a tool like Character Map
//to copy and paste the glyph into your IDE
//saving it as a variable makes it much easier to work with
String hexagonGlyph = ""
String triangleGlyph = ""
....whatever code you got...
//arguments: text, x coordinate, y coordinate, paint
canvas.drawText(hexagonGlyph, 200, 100, stopSignPaint);
//make it into a go sign
stopSignPaint.setColor(Color.Green);
canvas.drawText(hexagonGlyph, 200, 100, stopSignPaint);
//make a tiny one
stopSignPaint.setTextSize(20);
stopSignPaint.setColor(Color.RED);
canvas.drawText(hexagonGlyph, 200, 100, stopSignPaint);
//make a triangle
canvas.drawText(triangleGlyph, 200, 100, stopSignPaint);
drawPolygonPath()
即可。class PolygonView : View {
constructor(context: Context?) : super(context) {
init()
}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
init()
}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
init()
}
private lateinit var paint: Paint
private fun init() {
paint = Paint().apply {
color = Color.RED
isAntiAlias = true
style = Paint.Style.FILL
strokeWidth = 10f
}
}
override fun onDraw(canvas: Canvas) {
canvas.drawPath(drawPolygonPath(8, 150f), paint)
canvas.drawPath(drawPolygonPath(5, 120f), paint)
}
/**
* @param sides number of polygon sides
* @param radius side length.
* @param cx drawing x start point.
* @param cy drawing y start point.
* */
private fun drawPolygonPath(
sides: Int,
radius: Float,
cx: Float = radius,
cy: Float = radius
): Path {
val path = Path()
val x0 = cx + (radius * cos(0.0).toFloat())
val y0 = cy + (radius * sin(0.0).toFloat())
//2.0 * Math.PI = 2π, which means one circle(360)
//The polygon total angles of the sides must equal 360 degree.
val angle = 2 * Math.PI / sides
path.moveTo(x0, y0)
for (s in 1 until sides) {
path.lineTo(
cx + (radius * cos(angle * s)).toFloat(),
cy + (radius * sin(angle * s)).toFloat()
)
}
path.close()
return path
}
}
试一试这个,或者查看完整演示
Paint paint = new Paint();
paint.setColor(Color.parseColor("#BAB399"));
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
Path.lineTo(x0, y0)
,你可以直接调用Path.close()
来自动添加闭合线段。 - ralfoide