2014-07-24 8 views
6

Es gibt etwas, das ich inhere vermisse, so hoffe ich, dass Sie etwas Licht auf mich teilen können.Ziehen gedrehten Text in Android-Canvas funktioniert nicht wie erwartet

Ich zeichne etwas Text in Canvas. Dazu habe ich eine Klasse Word

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

Die App der Benutzer den Text zu drehen erlaubt, und ich übernehmen die Rotation 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(); 
} 

Das Problem, das ich bekommen ist, wenn der Benutzer die Leinwand zieht und Es gibt einen Rotationssatz. Wenn der Winkel = 0 ist, läuft die Bewegung wie erwartet.

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

und auf dragWords für jedes Wort, das ich tun:

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

}

Wenn Drehwinkel 0,/Bewegen nach oben nach unten/links/rechts macht die Worte um die gleiche Strecke bewegen . Wenn der Winkel größer wird, beginnen sich die Wörter in verschiedenen Richtungen zu bewegen, zum Beispiel bei 60 beginnt sie diagonal nach oben zu gehen, bei 180 bewegt sie sich nur nach oben/unten und nicht nach links/rechts.

Ich denke, ich muss eine Art von einem Unterschied basierend auf Winkel berechnen und es zu xMovement/yMovement hinzufügen ... aber wie soll ich das tun?

LE: Hier ist ein Bild, wie es sich verhält: enter image description here Die blauen Linien sind, wie der Text auf Drag bewegt, während die orange der Finger auf dem Bildschirm bewegen. Wenn der Winkel 0 ist, funktioniert er ziemlich gut, wenn der Winkel zunimmt, beginnt er, sich diagonal nach links/rechts zu bewegen, während er, wenn der Winkel noch größer ist, nur nach oben und unten bewegt wird und nicht auf links/rechts reagiert

Antwort

0

Im ellipses Teil in dem folgenden Code:

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

initialX = currentX; 
initialY = currentY; 

Andernfalls Ihre x- und y-Werte entsprechen nicht korrekt mit der Betrag der Entfernung, die während der Berührungsgeste bewegt wurde.

Als Benutzer matiash angegeben, sollten Sie Matrix#mapPoints(float[]) verwenden, um Ihre X- und Y-Werte zu transformieren. Deklarieren und eine Matrix initialisieren:

Matrix correctionMatrix; 

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

Hier ist, wie Sie Ihre onDraw(Canvas) aussehen sollte:

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

Sie Dies sollte geben die gewünschten Ergebnisse - Bewegung in der X- und Y-Achse unabhängig von Leinwand Rotation.

Sie können den Anruf natürlich zu setRotate(float, float, float) an einen besseren Ort verschieben. Sie müssen es nur einmal aufrufen, nachdem Sie den Wert angle geändert haben.

+0

Ich sehe wirklich nicht den Unterschied zwischen dieser Lösung und das Wesentliche habe ich gepostet (?) – matiash

+0

Es ist in der Tat der gleiche Ansatz, es war nur ein bisschen einfacher, nur auf Matrix mit -global – Alin

+0

@matiash Ich gab nur das Wesentliche Sie einen Probe-Lauf geschrieben - funktioniert gut, außer einem nicht verwandten Problem (nicht wichtig). Die Sache ist, ich ging deine Antwort durch und sah, dass 'Alin' keinen Erfolg damit hatte. Also habe ich selbstständig mit der Idee codiert, dass die Rotation neutralisiert werden muss (unter Verwendung der Negation des Rotationswinkels). – Vikram

3

Wenn I richtig verstanden, das Problem ist, dass Canvas.rotate() nicht nur die Textrichtung, sondern die ganze Leinwand dreht. Daher werden die x-y-Koordinaten der Wörter ebenfalls von dem spezifizierten Drehpunkt aus gedreht.

Um die Verschiebungsbewegung anzupassen, können Sie hierfür eine Matrix verwenden, genauer gesagt die inverse matrix desjenigen, den Sie zum Drehen der Zeichenfläche verwenden. Es wird verwendet, um die X-Y-Koordinaten der Wörter in ihre ursprünglichen Vordrehungsorte zu konvertieren.

Berechnen Sie dies beispielsweise einmal und aktualisieren Sie es, wenn sich angle, centerX oder centerY ändert.

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

Dann, wenn jedes Wort Zeichnung:

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

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

Ich werde das heute testen, danke für Ihre Antwort. Ich habe vorher versucht, eine Matrix wie 'matrix.setRotate (-Maigle, centerX, centerY)' und dann mapPoints zu benutzen, aber es hat nicht richtig funktioniert. – Alin

+0

Ich brauche canvas.rotate wegen anderer Operationen, die ich in der Ansicht mache. Das Drehen der Leinwand funktioniert ziemlich gut, wenn ich zum Beispiel ein Bild rotiere, sogar das Ziehen funktioniert für Bilder, aber ich weiß nicht, warum das für Wörter nicht so ist. Ich bin mir nicht sicher, ob ich deine Antwort wirklich verstehe. – Alin

+0

@Alin Entschuldigung, ich war nicht klar. Was ich meinte, war, alles so wie du zu behalten, einschließlich canvas.rotate, aber füge diesen zusätzlichen Code hinzu. – matiash