私はAndroidにかなり慣れておらず、Canvasをいじっています。矢印を描画しようとしていますが、シャフトを描画するだけで運が良かったので、矢印が機能していません。 。
少し検索して、Javaの例を見つけましたが、AndroidにはGeneralPath
またはAffineTransform
がありません。
今のところ、私のコードは次のようになっています(矢じりは矢じりのようには見えません):
public class DrawableView extends View {
Context mContext;
private int centerX;
private int centerY;
private int radius;
private double arrLength;
private double arrHeading;
private int margin = 10;
public DrawableView(Context context) {
super(context);
mContext = context;
}
@Override
protected void onDraw(Canvas canvas) {
//Paint Background
Paint background = new Paint();
background.setColor(getResources().getColor(R.color.background);
canvas.drawRect(0, 0, getWidth(), getHeight(), background);
//Set vars for Arrow Paint
Paint paint = new Paint();
Paint.setColor(getResources().getColor(R.color.arrowColor);
centerX = getWidth() / 2;
centerY = getHeight() / 2;
arrLength = radius - 10;
if(centerX < centerY)
radius = centerX - margin;
else
radius = centerY - margin;
//Draw Shaft
int[] xy = findArrowPos(arrLength, arrHeading);
canvas.drawLine(centerX, centerY, xy[0], xy[1], Paint);
//Draw ArrowHead
//This is where I'm confused
}
private int[] findArrowPos(double length, double angle) {
int[] points = new int[2];
double theta = Math.toRadians(angle);
points[0] = centerX + (int) (length * Math.cos(theta));
points[1] = centerY + (int) (length * Math.sin(theta));
return points;
}
}
ガイダンスとして、次のスレッドを確認しました。
* http://www.Java-forums.org/awt-swing/6241-how-u-rotate-arrow-mark-line-moves-accordingly.html
* Javaで有向矢印線を描画する方法は?
「PathmyPath = newPath();」を使用するのはどうですか。ここで、xとyの位置を指定して、線を使用して三角形を作成し、それを塗りつぶします。あなたはそれについて読むことができます、これは私がどこかから取った例です。
// 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);
私はそれが完全に機能しているこのコードを試します:
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;
}
私の矢印描画コード、多分それは誰かのためにいくらか役に立つかもしれません:
/**
* 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);
}
私は同じ問題を抱えています。特定の方向を指す矢印が必要です。描画アルゴリズムを試してみた後、最も簡単な方法はビットマップを使用し、マトリックスを使用して回転させることであると判断しました。
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);
次に、ビットマップは、好きなように見える任意の矢印にすることができます。
固定長の見出しで、1秒間に数千の矢印を描画するソリューションを探している場合は、次の機能を試してください(矢印の頭のみを描画します)。
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);
}
に基づく https://gamedev.stackexchange.com/questions/44456/drawing-lines-on-Android-with-matrix
以下のように Path を使用し、それに応じて座標を調整します。
// Construct a wedge-shaped path
Path mPath = new Path();
mPath.moveTo(0, -50);
mPath.lineTo(-20, 60);
mPath.lineTo(0, 50);
mPath.lineTo(20, 60);
mPath.close();
これは、キャンバスに線を描きながら矢印を描くのに最適なコードです。
package com.example.canvasexample;
import Android.content.Context;
import Android.graphics.Canvas;
import Android.graphics.Color;
import Android.graphics.Matrix;
import Android.graphics.Paint;
import Android.graphics.Path;
import Android.support.annotation.NonNull;
import Android.util.AttributeSet;
import Android.util.Log;
import Android.view.MotionEvent;
import Android.view.View;
import Java.util.ArrayList;
import static Android.view.MotionEvent.ACTION_DOWN;
import static Android.view.MotionEvent.ACTION_MOVE;
import static Android.view.MotionEvent.ACTION_UP;
public class DrawerViewArrow extends View {
private ArrayList<Path> drawingLinePath;
private ArrayList<Path> drawingArrowPath;
private ArrayList<Paint> drawingLinePaint;
private int pathIndex = 0;
private float startX = -1, startY = -1;
private float mX = -1, mY = -1;
public int arrowLength = 80;
public int arrowWidth = 45;
public int strokeWidth = 10;
public DrawerViewArrow(Context context) {
super(context);
initPath();
}
public DrawerViewArrow(Context context, @NonNull AttributeSet attrs) {
super(context, attrs);
initPath();
}
public DrawerViewArrow(Context context, @NonNull AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPath();
}
private Paint initPaint() {
Paint mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(strokeWidth);
return mPaint;
}
private void initPath() {
drawingLinePath = new ArrayList<>();
drawingArrowPath = new ArrayList<>();
drawingLinePath.add(new Path());
drawingArrowPath.add(new Path());
drawingLinePaint = new ArrayList<>();
drawingLinePaint.add(initPaint());
pathIndex++;
}
private Path createPath(MotionEvent event) {
Path path = new Path();
path.moveTo(event.getX(), event.getY());
return path;
}
private void updateIndex(MotionEvent event) {
if (pathIndex == drawingLinePath.size()) {
drawingLinePath.add(createPath(event));
drawingArrowPath.add(createPath(event));
drawingLinePaint.add(initPaint());
pathIndex++;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (startX > -1 && mX > -1) {
canvas.drawLine(startX, startY, mX, mY, initPaint());
drawArrow(canvas);
}
for (int index = 0; index < pathIndex; index++) {
Path path = drawingLinePath.get(index);
Path arrow_path = drawingArrowPath.get(index);
Paint paint = drawingLinePaint.get(index);
canvas.drawPath(path, Paint);
canvas.drawPath(arrow_path, Paint);
}
}
private void drawArrow(Canvas canvas) {
double angle = calculateAngle(startX, startY, mX, mY);
float final_angle = (float) (180 - angle);
Path arrow_path = new Path();
Matrix arrow_matrix = new Matrix();
arrow_matrix.postRotate(final_angle, mX, mY);
arrow_path.moveTo(mX, mY);
arrow_path.lineTo(mX - arrowWidth, mY + arrowLength);
arrow_path.moveTo(mX, mY);
arrow_path.lineTo(mX + arrowWidth, mY + arrowLength);
arrow_path.lineTo(mX - (arrowWidth), mY + arrowLength);
arrow_path.transform(arrow_matrix);
canvas.drawPath(arrow_path, initPaint());
}
private void saveArrow() {
if (mX == -1 || mY == -1) {
return;
}
double angle = calculateAngle(startX, startY, mX, mY);
float final_angle = (float) (180 - angle);
Path arrow_path = drawingArrowPath.get(pathIndex - 1);
Matrix arrow_matrix = new Matrix();
arrow_matrix.postRotate(final_angle, mX, mY);
arrow_path.moveTo(mX, mY);
arrow_path.lineTo(mX - arrowWidth, mY + arrowLength);
arrow_path.moveTo(mX, mY);
arrow_path.lineTo(mX + arrowWidth, mY + arrowLength);
arrow_path.lineTo(mX - (arrowWidth), mY + arrowLength);
arrow_path.transform(arrow_matrix);
}
public double calculateAngle(double x1, double y1, double x2, double y2) {
double angle = Math.toDegrees(Math.atan2(x2 - x1, y2 - y1));
angle = angle + Math.ceil(-angle / 360) * 360; //Keep angle between 0 and 360
return angle;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case ACTION_UP:
actionUp(event);
break;
case ACTION_MOVE:
actionMove(event);
break;
case ACTION_DOWN:
actionDown(event);
break;
}
invalidate();
return true;
}
private void actionDown(MotionEvent event) {
updateIndex(event);
startX = event.getX();
startY = event.getY();
}
private void actionMove(MotionEvent event) {
mX = event.getX();
mY = event.getY();
}
private void actionUp(MotionEvent event) {
drawingLinePath.get(pathIndex - 1).lineTo(event.getX(), event.getY());
saveArrow();
startX = -1;
startY = -1;
mX = -1;
mY = -1;
}
}