J'essaie de faire pivoter un dessin dans une vue en le touchant et en déplaçant le doigt. J'ai trouvé plusieurs solutions, mais aucune ne semble naturelle sur l'appareil.Android: Comment faire pivoter un élément en le touchant?
Voici ma première approche: Selon l'endroit où l'utilisateur a touché l'écran et dans quelle direction le doigt a été déplacé, je change la rotation de l'étirable, calculée plus ou moins arbitrairement.
private void updateRotation(float x, float y, float oldX, float oldY) {
int width = getWidth();
int height = getHeight();
float centerX = width/2;
float centerY = height/2;
float xSpeed = rotationSpeed(x, oldX, width);
float ySpeed = rotationSpeed(y, oldY, height);
if ((y < centerY && x > oldX)
|| (y > centerY && x < oldX))
rotation += xSpeed;
else if ((y < centerY && x < oldX)
|| (y > centerY && x > oldX))
rotation -= xSpeed;
if ((x > centerX && y > oldY)
|| (x < centerX && y < oldY))
rotation += ySpeed;
else if ((x > centerX && y < oldY)
|| (x < centerX && y > oldY))
rotation -= ySpeed;
}
private static float rotationSpeed(float pos, float oldPos, float max) {
return (Math.abs(pos - oldPos) * 180)/max;
}
Cette approche a eu quelques effets secondaires gênants: Parfois, la drawable tournerait alors que le doigt ne bougeait pas et la rotation était généralement pas aussi vite que le doigt de l'utilisateur. J'ai donc jeté ce code et j'ai commencé ma seconde approche. J'utilise la trigonométrie pour calculer la rotation réelle qui serait équivalent au mouvement des doigts:
private void updateRotation(float x, float y, float oldX, float oldY) {
float centerX = getWidth()/2;
float centerY = getHeight()/2;
float a = distance(centerX, centerY, x, y);
float b = distance(centerX, centerY, oldX, oldY);
float c = distance(x, y, oldX, oldY);
double r = Math.acos((Math.pow(a, 2) + Math.pow(b, 2) - Math.pow(c, 2))
/(2 * a * b));
if ((oldY < centerY && x < oldX)
|| (oldY > centerY && x > oldX)
|| (oldX > centerX && y < oldY)
|| (oldX < centerX && y > oldY))
r *= -1;
rotation += (int) Math.toDegrees(r);
}
private float distance(float x1, float y1, float x2, float y2) {
return Math.abs(x1 - x2) + Math.abs(y1 - y2);
}
Bien que cela ne semble que pour moi la bonne solution, il ne fonctionne pas bien non plus. Le mouvement des doigts est parfois ignoré - le calcul peut-il être trop coûteux? De plus, la rotation est encore un peu plus rapide que le mouvement réel du doigt.
Idéalement, si je commence à faire tourner l'emboutissage en touchant un point spécifique, ce point devrait rester sous le doigt à tout moment. Pouvez-vous me dire comment y parvenir?
Edit:
Voici mon adoption de la suggestion de Snailer. Je devais passer les arguments pour la méthode atan2
pour tourner dans la bonne direction, maintenant il fonctionne très bien:
private void updateRotation(float x, float y) {
double r = Math.atan2(x - getWidth()/2, getHeight()/2 - y);
rotation = (int) Math.toDegrees(r);
}
Le code est plus court maintenant, mais il ne fonctionne pas vraiment, le mouvement est presque aléatoire. J'ai ajouté mon post original pour incorporer cette solution. – fhd
Nevermind vous solution fonctionne. Il y avait un problème avec mon code destiné à arrêter la rotation à 0 ou 360 degrés. Je l'ai enlevé de la question, car ce n'est pas vraiment pertinent. Cela vous dérangerait-il d'expliquer les calculs de votre réponse? – fhd
Oh oui, j'aurais dû mentionner cette méthode renvoie (0-180) ou (0-180), ce qui dessine bien .. mais évidemment si vous vérifiez l'angle ailleurs dans le code, vous voulez savoir ce. Les mathématiques ne sont pas les miennes. Je suis tombé sur une formule quelque part sur ce site et l'ai modifié un peu pour ma propre utilisation, mais je n'arrive pas à trouver la question à nouveau. – Snailer