How do I draw an arrowhead (in Android)?

Solution 1:

How about using "Path myPath = new Path();" where you would give the x and y positions to create a triangle using lines and filling it. You can read about it, here is an example I took from somewhere.

// create and draw triangles
// use a Path object to store the 3 line segments
// use .offset to draw in many locations
// note: this triangle is not centered at 0,0
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.RED);
Path path = new Path();
path.moveTo(0, -10);
path.lineTo(5, 0);
path.lineTo(-5, 0);
path.close();
path.offset(10, 40);
canvas.drawPath(path, paint);
path.offset(50, 100);
canvas.drawPath(path, paint);
// offset is cumlative
// next draw displaces 50,100 from previous
path.offset(50, 100);
canvas.drawPath(path, paint);

Solution 2:

My Arrow Drawing code, maybe it can be of some use for somebody:

    /**
 * Draw an arrow
 * change internal radius and angle to change appearance
 * - angle : angle in degrees of the arrows legs
 * - radius : length of the arrows legs
 * @author Steven Roelants 2017
 *
 * @param paint
 * @param canvas
 * @param from_x
 * @param from_y
 * @param to_x
 * @param to_y
 */
private void drawArrow(Paint paint, Canvas canvas, float from_x, float from_y, float to_x, float to_y)
{
    float angle,anglerad, radius, lineangle;

    //values to change for other appearance *CHANGE THESE FOR OTHER SIZE ARROWHEADS*
    radius=10;
    angle=15;

    //some angle calculations
    anglerad= (float) (PI*angle/180.0f);
    lineangle= (float) (atan2(to_y-from_y,to_x-from_x));

    //tha line
    canvas.drawLine(from_x,from_y,to_x,to_y,paint);

    //tha triangle
    Path path = new Path();
    path.setFillType(Path.FillType.EVEN_ODD);
    path.moveTo(to_x, to_y);
    path.lineTo((float)(to_x-radius*cos(lineangle - (anglerad / 2.0))),
            (float)(to_y-radius*sin(lineangle - (anglerad / 2.0))));
    path.lineTo((float)(to_x-radius*cos(lineangle + (anglerad / 2.0))),
            (float)(to_y-radius*sin(lineangle + (anglerad / 2.0))));
    path.close();

    canvas.drawPath(path, paint);
}

Solution 3:

I try this code it has been working perfectly:

switch (event.getAction())
{
   case MotionEvent.ACTION_DOWN:
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
        startPoint = new PointF(event.getX(), event.getY());
        endPoint = new PointF();
        invalidate();
        break;
    case MotionEvent.ACTION_MOVE:
            float dx = Math.abs(x - mX);
        System.out.println("action move");
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
        {
        //  currentDrawingPath.path.quadTo(mX,mY,(x + mX)/2, (y + mY)/2);
        }
        mX = x;
        mY = y;
          endPoint.x = event.getX();
          endPoint.y = event.getY();
          isDrawing = true;
          invalidate();
        break;
    case MotionEvent.ACTION_UP:
           mPath.lineTo(mX, mY);
           float deltaX =   endPoint.x-startPoint.x;
           float deltaY =   endPoint.y-startPoint.y;
           float frac = (float) 0.1;
     float point_x_1 = startPoint.x + (float) ((1 - frac) * deltaX + frac * deltaY);
     float point_y_1 = startPoint.y + (float) ((1 - frac) * deltaY - frac * deltaX);
           float point_x_2 = endPoint.x;
           float point_y_2 = endPoint.y;
     float point_x_3 = startPoint.x + (float) ((1 - frac) * deltaX - frac * deltaY);
     float point_y_3 = startPoint.y + (float) ((1 - frac) * deltaY + frac * deltaX);
           mPath.moveTo(point_x_1, point_y_1);
           mPath.lineTo(point_x_2, point_y_2);
           mPath.lineTo(point_x_3, point_y_3);
           mPath.lineTo(point_x_1, point_y_1);
           mPath.lineTo(point_x_1, point_y_1);
            mCanvas.drawPath(mPath, ppaint);
            endPoint.x = event.getX();
            endPoint.y = event.getY();
            isDrawing = false;
            invalidate();
        break;
    default:
        break;
}       

Solution 4:

I've been having the same problem, I need an arrow to point in a certain direction. After playing around with drawing algorithms I decided the simplest method is to use a bitmap & simply use a Matrix to rotate it, e.g.

ImageView image = (ImageView) findViewById(R.id.bitmap_image);
Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
Matrix mat = new Matrix();
mat.postRotate(90);
Bitmap bMapRotate = Bitmap.createBitmap(bMap, 0, 0, bMap.getWidth(), bMap.getHeight(), mat, true);
image.setImageBitmap(bMapRotate);

then your bitmap can be any fancy looking arrow you like.

Solution 5:

If you are looking for the solution to draw thousands of arrows under a second, with fixed length head lines, try this function (draws only arrow heads):

private void fillArrow(Paint paint, Canvas canvas, float x0, float y0, float x1, float y1) {
    paint.setStyle(Paint.Style.STROKE);

    int arrowHeadLenght = 10;
    int arrowHeadAngle = 45;
    float[] linePts = new float[] {x1 - arrowHeadLenght, y1, x1, y1};
    float[] linePts2 = new float[] {x1, y1, x1, y1 + arrowHeadLenght};
    Matrix rotateMat = new Matrix();

    //get the center of the line
    float centerX = x1;
    float centerY = y1;

    //set the angle
    double angle = Math.atan2(y1 - y0, x1 - x0) * 180 / Math.PI + arrowHeadAngle;

    //rotate the matrix around the center
    rotateMat.setRotate((float) angle, centerX, centerY);
    rotateMat.mapPoints(linePts);
    rotateMat.mapPoints(linePts2);

    canvas.drawLine(linePts [0], linePts [1], linePts [2], linePts [3], paint);
    canvas.drawLine(linePts2 [0], linePts2 [1], linePts2 [2], linePts2 [3], paint);
}

Based on https://gamedev.stackexchange.com/questions/44456/drawing-lines-on-android-with-matrix