How to draw filled triangle on android Canvas-ThrowExceptions

Exception or error:

I have class MyView that extends View class. MyView should draw filled triangle. I drew a triangle but I cannot get it filled. This is my onDraw() method:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Paint paint = new Paint();

    paint.setColor(android.graphics.Color.BLACK);
    canvas.drawPaint(paint);

    paint.setStrokeWidth(4);
    paint.setColor(android.graphics.Color.RED);
    paint.setStyle(Paint.Style.FILL_AND_STROKE);
    paint.setAntiAlias(true);

    Point a = new Point(0, 0);
    Point b = new Point(0, 100);
    Point c = new Point(87, 50);

    Path path = new Path();
    path.setFillType(FillType.EVEN_ODD);
    path.moveTo(a.x, a.y);
    path.lineTo(b.x, b.y);
    path.moveTo(b.x, b.y);
    path.lineTo(c.x, c.y);
    path.moveTo(c.x, c.y);
    path.lineTo(a.x, a.y);
    path.close();

    canvas.drawPath(path, paint);
}

This is what I get as a result:

enter image description here

How to solve:

I’ve found the answer

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Paint paint = new Paint();

    paint.setColor(android.graphics.Color.BLACK);
    canvas.drawPaint(paint);

    paint.setStrokeWidth(4);
    paint.setColor(android.graphics.Color.RED);
    paint.setStyle(Paint.Style.FILL_AND_STROKE);
    paint.setAntiAlias(true);

    Point a = new Point(0, 0);
    Point b = new Point(0, 100);
    Point c = new Point(87, 50);

    Path path = new Path();
    path.setFillType(FillType.EVEN_ODD);
    path.lineTo(b.x, b.y);
    path.lineTo(c.x, c.y);
    path.lineTo(a.x, a.y);
    path.close();

    canvas.drawPath(path, paint);
}

###

This answer provides a bit of clarity on where the numbers given in the answer by @Egis come from. (this will draw an upside down equilateral triangle and is written in kotlin)

class TriangleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {

    val paint = Paint()
    val path = Path()

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas ?: return
        canvas.drawPath(configurePath(canvas.width.toFloat(), path), configurePaint(paint))
    }

    fun getHeight(width: Double): Float {
        return Math.sqrt((Math.pow(width, 2.0) - Math.pow((width / 2), 2.0))).toFloat()
    }

    fun configurePaint(paint: Paint): Paint {
        paint.color = android.graphics.Color.WHITE
        paint.isAntiAlias = true

        return paint
    }

    fun configurePath(width: Float, path: Path): Path {
        path.lineTo((width / 2f), getHeight(width.toDouble()))
        path.lineTo(width, 0F)
        path.lineTo(0f, 0f)

        return path
    }
}

The get height function is Pythagoras’ Theorem and will always find the height of an equilateral triangle to be ~87% of its side length

Gist can be found here, it contains code for the other direction

###

I recently created a small demo app drawing various shapes, including triangles, rectangles and spirals. Here is the code for drawing the triangles. For full context, reference the project. In this app, the user can draw a triangle as a single drawing or a composition of two triangles forming into one as the user scrolls. The increasing triangle growth is accomplished through the principles of Triangle Similarity, with each smaller triangle similar to the large triangle in the end.

Project: https://github.com/jdgreene2008/android_custom_views

Source Excerpt: https://github.com/jdgreene2008/android_custom_views/blob/master/CustomUiComponents/app/src/main/java/com/jarvis/dragdropresearch/views/FlashShapeView.java

 private void drawTriangleShape(Canvas canvas, RectF bounds,
            TriangleInterpolator triangleInterpolator, Paint paint) {
        paint.setStyle(Paint.Style.FILL);

        float baseInterpolation = triangleInterpolator
                .getInterpolatedValues()[TriangleInterpolator.INTERPOLATION_VALUES_BASE];
        float altitudeInterpolation = triangleInterpolator
                .getInterpolatedValues()[TriangleInterpolator.INTERPOLATION_VALUES_ALTITUDE];

        // *** Construct the Left Triangle ** //

        // Bottom left vertex
        float bottomLeftX = bounds.left;
        float bottomLeftY = bounds.bottom;

        // Bottom right corner
        float bottomRightX = bottomLeftX + baseInterpolation;
        float bottomRightY = bounds.bottom;

        //Top Vertex
        float topX = bottomRightX;
        float topY = bottomRightY - altitudeInterpolation;

        Path leftTriangle = new Path();
        leftTriangle.lineTo(bottomLeftX, bottomLeftY);
        leftTriangle.lineTo(bottomRightX, bottomRightY);
        leftTriangle.lineTo(topX, topY);
        leftTriangle.lineTo(bottomLeftX, bottomLeftY);

        canvas.drawPath(leftTriangle, paint);

        if (triangleInterpolator.isSymmetric()) {
            // *** Construct the Right Triangle ** //

            bottomLeftX = bounds.right - baseInterpolation;
            bottomLeftY = bounds.bottom;

            bottomRightX = bounds.right;
            bottomRightY = bounds.bottom;

            topX = bottomLeftX;
            topY = bottomRightY - altitudeInterpolation;

            Path rightTriangle = new Path();
            rightTriangle.lineTo(bottomLeftX, bottomLeftY);
            rightTriangle.lineTo(bottomRightX, bottomRightY);
            rightTriangle.lineTo(topX, topY);
            rightTriangle.lineTo(bottomLeftX, bottomLeftY);

            canvas.drawPath(rightTriangle, paint);
        }
    }

###

these links are very usefull.

  1. https://github.com/swapgo20/Android-Hand-Drawing
  2. https://github.com/codepath/android_guides/wiki/Basic-Painting-with-Views
  3. https://github.com/Korilakkuma/CanvasView

###

I would like to point out that you should never initiialize an object from onDraw() as it gets called multiple times and leads to performance problems.

Leave a Reply

Your email address will not be published. Required fields are marked *