Acerte um relógio analógico com gestos, tocando o ponteiro dos minutos no sentido horário ou anti-horário
-
21-12-2019 - |
Pergunta
Estou tentando criar uma classe que permita aos usuários acertar um relógio analógico na hora certa.Eles precisam mover o ponteiro dos minutos, não o ponteiro das horas, no sentido horário ou anti-horário para definir a hora atual.O ponteiro das horas se move de acordo com o progresso do ponteiro dos minutos, mas não consigo mover o ponteiro das horas corretamente.Não tem um movimento suave toda vez que passa das doze horas e das seis horas, onde há pontos críticos de ângulo.
Este é o meu treino até o momento.Às doze horas o ângulo é igual a 0 graus, o ângulo mínimo do curso, e às seis horas o ângulo é de 180 graus, o ângulo máximo.Assim, de doze a seis (sentido horário), temos ângulos positivos (0,180), e, de seis a doze (sentido horário), temos ângulos negativos (-180,0).Tudo bem, mas se eu quiser calcular qual será a posição correta do ponteiro das horas de acordo com o progresso do ponteiro dos minutos, tenho que traduzir esses ângulos para a faixa de 0 a 360 graus.
Aqui é onde eu lido com gestos:
@Override
public boolean onTouch(View v, MotionEvent event) {
// Clock is the clock sphere and the minutes hand.
final float xc = clock.getTranslationX() + (clock.getWidth() / 2);
final float yc = clock.getTranslationY() + (clock.getHeight() / 2);
final float x = event.getX();
final float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
clock.clearAnimation();
mMinutesCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
break;
case MotionEvent.ACTION_MOVE:
/**
* Translate angles from [-179,179] to [0,360] to be able to move
* hours hand properly.
*/
// Start Angle
mMinutesCurrAngle = set360Angle(mMinutesCurrAngle);
mMinutesPrevAngle = mMinutesCurrAngle;
// Finish angle
mMinutesCurrAngle = Math.toDegrees(Math.atan2(event.getX() - xc, yc - event.getY()));
mMinutesCurrAngle = set360Angle(mMinutesCurrAngle);
if ((mMinutesCurrAngle > mMinutesPrevAngle)) {
// Clockwise between 12 and 6
mHoursCurrAngle = mLastSpinHoursAngle + (mMinutesCurrAngle / 12);
} else if ((mMinutesCurrAngle < mMinutesPrevAngle)) {
// counter-Clockwise between 6 and 12
mHoursCurrAngle = mLastSpinHoursAngle + (mMinutesCurrAngle / 12);
} else if ((mMinutesCurrAngle > mMinutesPrevAngle) && (mMinutesCurrAngle < 0)) {
// Clockwise between 6 and 12
mHoursCurrAngle = mLastSpinHoursAngle + (- mMinutesCurrAngle / 12);
} else if ((mMinutesCurrAngle < mMinutesPrevAngle) && (mMinutesCurrAngle < 0)) {
// counter-Clockwise between 6 and 12
mHoursCurrAngle = mLastSpinHoursAngle + (mMinutesCurrAngle / 12);
}
newSpin();
// Transelate angles to the original format to represent them properly.
mMinutesPrevAngle = translate360Angle(mMinutesPrevAngle);
mMinutesCurrAngle = translate360Angle(mMinutesCurrAngle);
animate(clock, mMinutesPrevAngle, mMinutesCurrAngle, 0);
animate(hour, mHoursPrevAngle, mHoursCurrAngle, 0);
mHoursPrevAngle = mHoursCurrAngle;
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
Aqui é onde eu traduzo ângulos:
/**
* Translate angles from [-179,179] to [0,360] to be able to move
* hours hand properly.
* @param minutesAngle
* @return
*/
private double set360Angle(double angle) {
if (angle < 0) return (360 + angle);
else return angle;
}
/**
* Transelate angles to the original format to represent them properly.
* @param angle
* @return
*/
private double translate360Angle(double angle) {
if (angle > 180) return (-360 + angle);
else return angle;
}
E aqui é onde eu sei se o ponteiro dos minutos inicia um novo giro:
private void newSpin() {
if (translate360Angle(mMinutesPrevAngle) < 0 && translate360Angle(mMinutesCurrAngle) > 0) {
// New Spin clockwise
// I must remember hour hand angle
mLastSpinHoursAngle = mHoursPrevAngle;
} else if (translate360Angle(mMinutesPrevAngle) > 0 && translate360Angle(mMinutesCurrAngle) < 0) {
// New Spin counter-clockwise
// I must remember hour hand angle
mLastSpinHoursAngle = mHoursPrevAngle;
}
}
Alguém pode me ajudar um pouco?se alguém puder me ajudar, prometo colocar seu nome na minha primeira filha ainda não nascida...estou brincando.
Solução
descobri onde estava o problema...
O problema eram as "condições if" dentro do método newSpin().Aqui, antes de verificar as condições, traduzi os ângulos para o formato original (de 0 graus a 180 graus, das doze às seis horas, no sentido horário, e de -180 graus a 0 graus, das seis às doze horas). 'relógio, sentido horário também).Então, em vez disso, verifique se o usuário inicia uma nova rotação com o ponteiro dos minutos. Ele estava adicionando/subtraindo uma nova rotação toda vez que o usuário passa das seis horas em vez das doze horas.
Então, eu consertei modificando essas condições e verificando os ângulos dos ponteiros dos minutos, anterior e atual, no formato 360 graus.Agora, se o ângulo anterior for maior que 355 graus e o ângulo atual for menor que 5 graus, adiciono um novo giro ao mSpinNumber.Da mesma forma, se o ângulo anterior for menor que 5 graus e o ângulo atual for maior que 355 graus, subtraio um giro para mSpinNumber.Também mudei o nome do método de newSpin() para calcularHourHandAngle().
private void calculateHourHandAngle() {
if ((mMinutesPrevAngle > 355) && (mMinutesCurrAngle < 5)) {
// New Spin clockwise
mSpinNumber++;
} else if ((mMinutesPrevAngle < 5) && (mMinutesCurrAngle > 355)) {
// New Spin counter-clockwise
mSpinNumber--;
}
mHoursCurrAngle = (mSpinNumber * (360/12)) + (mMinutesCurrAngle / 12);
}
Também me livrei de códigos desnecessários no método onTouch():
@Override
public boolean onTouch(View v, MotionEvent event) {
// Clock is the clock sphere and the minutes hand.
final float xc = clock.getTranslationX() + (clock.getWidth() / 2);
final float yc = clock.getTranslationY() + (clock.getHeight() / 2);
final float x = event.getX();
final float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
clock.clearAnimation();
hour.clearAnimation();
mMinutesCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
break;
case MotionEvent.ACTION_MOVE:
/**
* Translate angles from [-179,179] to [0,360] to be able to move
* hours hand properly.
*/
// Start Angle
mMinutesCurrAngle = set360Angle(mMinutesCurrAngle);
mMinutesPrevAngle = mMinutesCurrAngle;
// Finish angle
mMinutesCurrAngle = Math.toDegrees(Math.atan2(event.getX() - xc, yc - event.getY()));
mMinutesCurrAngle = set360Angle(mMinutesCurrAngle);
calculateHourHandAngle();
animate(clock, translate360Angle(mMinutesPrevAngle), translate360Angle(mMinutesCurrAngle), 0);
animate(hour, mHoursPrevAngle, mHoursCurrAngle, 0);
mHoursPrevAngle = mHoursCurrAngle;
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
Agora posso saber que horas acertou o usuário, pois sei a posição inicial dos ponteiros do relógio, o número de giros e o ângulo do ponteiro dos minutos.