Android 如何在画布上画三角形、星形、正方形或心形?

Android 如何在画布上画三角形、星形、正方形或心形?,android,draw,shapes,Android,Draw,Shapes,我可以使用在画布上画一个圆和一个矩形 path.addCircle() 及 path.addRect() 现在我想知道如何画三角形、星形、正方形或心形?你必须找出这些数字背后的数学原理。三角形和星形很容易画。以下是如何画一颗心: 要绘制特殊路径,您应该通过添加点、椭圆等来创建它们。画布支持指定路径的剪裁遮罩,因此您可以设置心脏的剪裁遮罩,将路径推送到矩阵,绘制心脏的内容,然后再次弹出它 这就是我在andriod上实现模拟2D页面卷曲效果所做的: 希望这有帮助 除了椭圆和矩形,您还需要这两种(至少

我可以使用
在画布上画一个圆和一个矩形
path.addCircle()

path.addRect()


现在我想知道如何画三角形、星形、正方形或心形?

你必须找出这些数字背后的数学原理。三角形和星形很容易画。以下是如何画一颗心:

要绘制特殊路径,您应该通过添加点、椭圆等来创建它们。画布支持指定路径的剪裁遮罩,因此您可以设置心脏的剪裁遮罩,将路径推送到矩阵,绘制心脏的内容,然后再次弹出它

这就是我在andriod上实现模拟2D页面卷曲效果所做的:


希望这有帮助

除了椭圆和矩形,您还需要这两种(至少):


例如:


画布上的文档:

对于未来的直接回答搜索者,我使用画布绘制了一个几乎对称的星形,如图所示:

主要工具是使用路径

假设您已安装:

Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);

Path path = new Path();
然后在onDraw中,您可以像下面一样使用路径。它可以适当地缩放到任何尺寸

@Override
protected void onDraw(Canvas canvas) {

    float mid = getWidth() / 2;
    float min = Math.min(getWidth(), getHeight());
    float fat = min / 17;
    float half = min / 2;
    float rad = half - fat;
    mid = mid - half;

    paint.setStrokeWidth(fat);
    paint.setStyle(Paint.Style.STROKE);

    canvas.drawCircle(mid + half, half, rad, paint);

    path.reset();

    paint.setStyle(Paint.Style.FILL);


        // top left
        path.moveTo(mid + half * 0.5f, half * 0.84f);
        // top right
        path.lineTo(mid + half * 1.5f, half * 0.84f);
        // bottom left
        path.lineTo(mid + half * 0.68f, half * 1.45f);
        // top tip
        path.lineTo(mid + half * 1.0f, half * 0.5f);
        // bottom right
        path.lineTo(mid + half * 1.32f, half * 1.45f);
        // top left
        path.lineTo(mid + half * 0.5f, half * 0.84f);

        path.close();
        canvas.drawPath(path, paint);

    super.onDraw(canvas);

}

此方法将返回一条在给定宽度的正方形内具有给定角数的路径。添加更多参数以处理小半径等情况

    private Path createStarBySize(float width, int steps) {
    float halfWidth = width / 2.0F;
    float bigRadius = halfWidth;
    float radius = halfWidth / 2.0F;
    float degreesPerStep = (float) Math.toRadians(360.0F / (float) steps);
    float halfDegreesPerStep = degreesPerStep / 2.0F;
    Path ret = new Path();
    ret.setFillType(FillType.EVEN_ODD);
    float max = (float) (2.0F* Math.PI);
    ret.moveTo(width, halfWidth);
    for (double step = 0; step < max; step += degreesPerStep) {
        ret.lineTo((float)(halfWidth + bigRadius * Math.cos(step)), (float)(halfWidth + bigRadius * Math.sin(step)));
        ret.lineTo((float)(halfWidth + radius * Math.cos(step + halfDegreesPerStep)), (float)(halfWidth + radius * Math.sin(step + halfDegreesPerStep)));
    }
    ret.close();
    return ret;
}
private Path createStarBySize(浮点宽度,整数步长){
浮动半宽=宽度/2.0F;
浮动大半径=半宽度;
浮动半径=半宽/2.0F;
浮点度数步长=(浮点)数学半径(360.0F/(浮点)步长);
浮动半度数跨步=度数跨步/2.0F;
路径ret=新路径();
ret.setFillType(FillType.偶数\奇数);
浮点最大值=(浮点)(2.0F*Math.PI);
返回移动到(宽度、半宽度);
对于(双步长=0;步长<最大值;步长+=度跨步){
ret.lineTo((浮动)(半宽+大半径*数学坐标(步长)),(浮动)(半宽+大半径*数学坐标(步长));
ret.lineTo((浮动)(半宽+半径*数学坐标(步长+半度跨步)),(浮动)(半宽+半径*数学坐标(步长+半度跨步));
}
ret.close();
返回ret;
}

如果你需要在正方形内画一颗星,你可以使用下面的代码

posX
posY
是包围星尖的正方形左上角的坐标(正方形实际上没有绘制)

size
是正方形的宽度和高度

a
是星星的顶端。路径是顺时针创建的

这决不是一个完美的解决方案,但它能很快完成工作

 public void drawStar(float posX, float posY, int size, Canvas canvas){

            int hMargin = size/9;
            int vMargin = size/4;

            Point a = new Point((int) (posX + size/2), (int) posY);
            Point b = new Point((int) (posX + size/2 + hMargin), (int) (posY + vMargin));
            Point c = new Point((int) (posX + size), (int) (posY + vMargin));
            Point d = new Point((int) (posX + size/2 + 2*hMargin), (int) (posY + size/2 + vMargin/2));
            Point e = new Point((int) (posX + size/2 + 3*hMargin), (int) (posY + size));
            Point f = new Point((int) (posX + size/2), (int) (posY + size - vMargin));
            Point g = new Point((int) (posX + size/2 - 3*hMargin), (int) (posY + size));
            Point h = new Point((int) (posX + size/2 - 2*hMargin), (int) (posY + size/2 + vMargin/2));
            Point i = new Point((int) posX, (int) (posY + vMargin));
            Point j = new Point((int) (posX + size/2 - hMargin), (int) (posY + vMargin));

            Path path = new Path();
            path.moveTo(a.x, a.y);
            path.lineTo(b.x, b.y);
            path.lineTo(c.x, c.y);
            path.lineTo(d.x, d.y);
            path.lineTo(e.x, e.y);
            path.lineTo(f.x, f.y);
            path.lineTo(f.x, f.y);
            path.lineTo(g.x, g.y);
            path.lineTo(h.x, h.y);
            path.lineTo(i.x, i.y);
            path.lineTo(j.x, j.y);
            path.lineTo(a.x, a.y);

            path.close();

            canvas.drawPath(path, paint);
}

对于每个需要心脏形状的人:

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Paint.Style;
    import android.graphics.Path;
    import android.view.View;

    public class Heart extends View {

        private Path path;

        private Paint paint;

        public Heart(Context context) {
            super(context);

            path = new Path();
            paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        }

            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);

                // Fill the canvas with background color
                canvas.drawColor(Color.WHITE);
                paint.setShader(null);

                float width = getContext().getResources().getDimension(R.dimen.heart_width);
                float height = getContext().getResources().getDimension(R.dimen.heart_height);

                // Starting point
                path.moveTo(width / 2, height / 5); 

                // Upper left path
                path.cubicTo(5 * width / 14, 0,
                        0, height / 15,
                        width / 28, 2 * height / 5);

                // Lower left path
                path.cubicTo(width / 14, 2 * height / 3,
                        3 * width / 7, 5 * height / 6,
                        width / 2, height);

                // Lower right path
                path.cubicTo(4 * width / 7, 5 * height / 6,
                        13 * width / 14, 2 * height / 3,
                        27 * width / 28, 2 * height / 5);

                // Upper right path
                path.cubicTo(width, height / 15,
                        9 * width / 14, 0,
                        width / 2, height / 5);

                paint.setColor(Color.RED);
                paint.setStyle(Style.FILL);
                canvas.drawPath(path, paint);

            }
    }
对不起,所有的数字,但这些对我来说效果最好:)结果如下:


使用Shape类的实例非常好)

 @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    HeartShape shape = new HeartShape();
    ShapeDrawable shapeDrawable = new ShapeDrawable(shape);
    shapeDrawable.setColorFilter(new LightingColorFilter(0, Color.BLUE));

    LinearLayout linearLayout = new LinearLayout(this);
    linearLayout.setLayoutParams(new LinearLayout.LayoutParams(350 * 3, 350 * 3));
    linearLayout.setBackground(shapeDrawable);

    setContentView(linearLayout);
  }
创建一个shape类,该类是render nice Heart

 public class HeartShape extends Shape {

  private final int INVALID_SIZE = -1;

  private Path mPath = new Path();
  private RectF mRectF = new RectF();

  private float mOldWidth = INVALID_SIZE;
  private float mOldHeight = INVALID_SIZE;

  private float mScaleX, mScaleY;

  public HeartShape() {

  }

  @Override
  public void draw(Canvas canvas, Paint paint) {
    canvas.save();
    canvas.scale(mScaleX, mScaleY);

    float width = mRectF.width();
    float height = mRectF.height();

    float halfWidth = width/2;
    float halfHeight = height/2;

    float stdDestX = 5 * width / 14;
    float stdDestY = 2 * height / 3;

    PointF point1 = new PointF(stdDestX, 0);
    PointF point2 = new PointF(0, height / 15);
    PointF point3 = new PointF(stdDestX / 5, stdDestY);
    PointF point4 = new PointF(stdDestX, stdDestY);

    // Starting point
    mPath.moveTo(halfWidth, height / 5);

    mPath.cubicTo(point1.x, point1.y, point2.x, point2.y, width / 28, 2 * height / 5);
    mPath.cubicTo(point3.x, point3.y, point4.x, point4.y, halfWidth, height);

    canvas.drawPath(mPath, paint);

    canvas.scale(-mScaleX, mScaleY, halfWidth, halfHeight);
    canvas.drawPath(mPath, paint);

    canvas.restore();
  }

  @Override
  protected void onResize(float width, float height) {
    mOldWidth = mOldWidth == INVALID_SIZE ? width : Math.max(1, mOldWidth);
    mOldHeight = mOldHeight == INVALID_SIZE ? height : Math.max(1, mOldHeight);

    width = Math.max(1, width);
    height = Math.max(1, height);

    mScaleX = width / mOldWidth;
    mScaleY = height / mOldHeight;

    mOldWidth = width;
    mOldHeight = height;


    mRectF.set(0, 0, width, height);
  }

  @Override
  public void getOutline(@NonNull Outline outline) {
    // HeartShape not supported outlines
  }

  @Override
  public HeartShape clone() throws CloneNotSupportedException {
    HeartShape shape = (HeartShape) super.clone();
    shape.mPath = new Path(mPath);
    return shape;
  }

}

您需要将复杂形状划分为基本形状。例如,您可以使用两个半圆和两条线绘制心脏。三角形-选择3个点并用drawLine()连接,或者更好地将阵列pf点传递到drawLine();回答我自己的问题,让星星指向北方:1。设置填充类型。绕组。2.将最大值设置为(2*PI-PI/2)。3.将ret.moveTo设置为(半宽度,0)。