在Android画布内拖动旋转的文本无法按预期方式工作

时间:2014-07-24 16:17:28

标签: java android geometry android-canvas trigonometry

我遗漏了一些东西,所以我希望你能分享一些关于我的事情。

我正在画布中绘制一些文字。为此,我有一个班级Word

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

该应用允许用户旋转文字,我使用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时,效果非常好,当角度增加时,它开始沿左/右对角移动,而当角度更大时,它只上下移动而不响应左/右

2 个答案:

答案 0 :(得分:3)

如果我理解正确,问题是Canvas.rotate()不仅会旋转文字方向,还会旋转整个画布。因此,单词的x-y坐标也会从指定的轴心点旋转。

为了匹配拖动动作,您可以使用Matrix,更具体地说,您可以使用inverse matrix来旋转画布。它将用于将单词的x-y坐标转换为其原始的预旋转位置。

例如,计算一次,并在anglecenterXcenterY更改时更新。

// 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);

答案 1 :(得分:0)

在以下代码的ellipses部分中:

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

initialX = currentX;
initialY = currentY;

否则,您的x和y值将与触摸手势期间移动的距离量无法正确对应。

如用户matiash所示,您应使用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值后,您只需要调用一次。