Перетаскивание повернутого текста внутри Android canvas не работает должным образом

есть что-то, чего мне не хватает, поэтому я надеюсь, что вы сможете поделиться со мной светом.

Я рисую текст внутри canvas. Для этого у меня есть класс Word

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

приложение позволяет пользователю вращать текст, и я обрабатываю вращение withing 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();
}

проблема, которую я получаю, - это когда пользователь перетаскивает холст, и есть набор вращения. Когда угол=0 движение идет как ожидалось.

@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);
   .....

и dragWords для каждое слово я:

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

}

когда угол поворота равен 0, перемещение вверх/вниз/влево/вправо заставляет слова двигаться на одинаковое расстояние. Как угол становится больше, слова начинают двигаться в пригороды, например в 60, он начинает идти по диагонали вверх, после 180 она двигается только вверх/вниз, а не влево/вправо.

Я думаю, что мне нужно вычислить какую-то разницу на основе угла и добавить ее в xMovement/yMovement... но как мне это сделать? ?

LE: вот изображение о том, как он ведет себя: enter image description here Синие линии - это то, как текст перемещается по перетаскиванию, в то время как оранжевый-это перетаскивание пальца по экрану. Когда угол равен 0, он работает довольно хорошо, когда угол увеличивается, он начинает двигаться по диагонали влево/вправо, а когда угол еще больше, он движется только вверх и вниз и не реагирует на left / right

2 ответов


на ellipses в следующий код:

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

initialX = currentX;
initialY = currentY;

в противном случае ваши значения x и y не будут правильно соответствовать количеству расстояния, перемещенного во время сенсорного жеста.

как указано, вы должны использовать Matrix#mapPoints(float[]) для преобразования значений x и y. Объявить и инициализировать матрицу:

Matrix correctionMatrix;

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

вот как ваш onDraw(Canvas) должен выглядеть так:

@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();
}

это должно дать вам желаемые результаты-движение в Ось X и Y независимо от вращения холста.

вы можете, очевидно, переместить вызов в setRotate(float, float, float) в лучшее место. Вам нужно только позвонить один раз после изменения angle значение.


если я правильно понимаю, проблема в том, что Canvas.rotate() не только поворачивает направление текста, но и весь холст. Поэтому координаты x-y слов также поворачиваются от указанной точки поворота.

чтобы соответствовать перемещению перетаскивания, вы можете использовать Matrix для этого, а именно обратная матрица того, который вы используете для поворота холста. Он будет использоваться для преобразования x-y координаты слов к их первоначальным, pre-rotate положениям.

например, вычислите это один раз и обновите его, когда angle, centerX или 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);

затем, при рисовании каждого слова:

int wordX = ... 
int wordY = ...
String text = ...

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