Acerte um relógio analógico com gestos, tocando o ponteiro dos minutos no sentido horário ou anti-horário

StackOverflow https://stackoverflow.com//questions/24039913

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.

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top