Dragging and dropping rotated text inside an android canvas does not work properly

There is something that I am missing, so I hope you can share a little light with it.

I draw text inside the canvas. For this, I have a Word class

 public class Word { private int x; private int y; private String text; } 

The application allows the user to rotate the text, and I handle the rotation using onDraw

 protected void onDraw(Canvas canvas) { canvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.rotate(angle, centerX, centerY) ... canvas.drawText(word.getText(), word.getX(), word.getY()) .... canvas.restore(); } 

The problem I get is when the user drags the canvas and the rotation set appears. When angle = 0, the movement is as expected.

 @Override public boolean onTouchEvent(MotionEvent event) { case MotionEvent.ACTION_DOWN: initialX = (int) event.getX(); initialY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: int currentX = (int) event.getX(); int currentY = (int) event.getY(); int xMovement = currentX - initialX; int yMovement = currentY - initialY; dragWords(xMovement, yMovement); ..... 

and dragWords for every word I make:

 private void dragText(int xMovement, int yMovement){ for (Word word : words) { word.setX(word.getX() + xMovement); word.setY(word.getY() + yMovement); } invalidate(); 

}

When the rotation angle is 0, moving up / down / left / right causes the words to move the same distance. As the angle becomes larger, the words begin to move in different modes, for example, at 60, he begins to go diagonally upwards, when he only moves up / down, and not left / right.

It seems to me that I need to calculate some difference based on the angle and add it to xMovement / yMovement ... but how do I do this?

LE: Here is an image of how he behaves: enter image description here The blue lines are the way the text moves when dragging, and the orange is the dragging of the finger on the screen. When the angle is 0, it works well enough, when the angle increases, it starts moving diagonally left / right, and when the angle is even larger, it only moves up and down and does not respond to left / right

+6
source share
2 answers

In the ellipses part in the following code:

 dragWords(xMovement, yMovement); ..... <<<--------------------- I hope you are updating initialX and initialY initialX = currentX; initialY = currentY; 

Otherwise, your x and y values โ€‹โ€‹will incorrectly correspond to the distance moved during touch gestures.

As indicated by matiash , you should use Matrix#mapPoints(float[]) to convert the x and y values. Declare and initialize the matrix:

 Matrix correctionMatrix; // Your view constructor public MyView() { .... correctionMatrix = new Matrix(); } 

Here's what your onDraw(Canvas) looks like:

 @Override protected void onDraw(Canvas canvas) { canvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.rotate(angle, centerX, centerY); ... // Neutralize the rotation correctionMatrix.setRotate(-angle, centerX, centerY); // Initialize a float array that holds the original coordinates float[] src = {word.getX(), word.getY()}; // Load transformed values into `src` array correctionMatrix.mapPoints(src); // `src[0]` and `src[1]` hold the transformed `X` and `Y` coordinates canvas.drawText(word.text, src[0], src[1], somePaint); .... canvas.restore(); } 

This should give you the desired results - moving along the X and Y axis regardless of the rotation of the canvas.

Obviously, you can transfer the call to setRotate(float, float, float) to a better place. You will need to call it once after changing the angle value.

0
source

If I understand correctly, the problem is that Canvas.rotate() not only rotates the direction of the text, but the entire canvas. Therefore, the xy coordinates of the words also rotate from the specified turning point.

To fit the drag, you can use the Matrix , namely the inverse matrix of the one you use to rotate the canvas. It will be used to transform the xy coordinates of words into their original, pre-rotated locations.

For example, calculate this once and update it whenever the values โ€‹โ€‹of angle , centerX or centerY .

 // rotMatrix is the same operation applied on the canvas. Matrix rotMatrix = new Matrix(); rotMatrix.postRotate(mAngle, centerX, centerY); // Invert it to convert x, y to their transformed positions. Matrix matrix = new Matrix(); rotMatrix.invert(matrix); 

Then, when drawing each word:

 int wordX = ... int wordY = ... String text = ... float[] coords = new float[] { wordX, wordY }; matrix.mapPoints(coords); canvas.drawText(text, coords[0], coords[1], paint); 
+3
source

Source: https://habr.com/ru/post/972783/


All Articles