Установите аналоговые часы на время жестами, касаясь минутной стрелки по часовой стрелке или против часовой стрелки

Я застрял, пытаясь создать класс, позволяющий пользователям устанавливать аналоговые часы вовремя. Они должны перемещать минутную стрелку, а не часовую стрелку, по часовой стрелке или против часовой стрелки, чтобы установить текущее время. Часовая стрелка перемещается в соответствии с ходом минутной стрелки, но я не могу правильно перемещать часовую стрелку. Он не имеет плавного движения каждый раз, когда проходит через двенадцать и шесть часов, где есть критические точки угла.

Это моя тренировка до этого момента. В двенадцать часов угол равен 0 градусам, минимальный угол курса, а в шесть часов угол равен 180 градусам, максимальный угол. Итак, с двенадцати до шести (по часовой стрелке) у нас положительные углы (0,180), а с шести до двенадцати (по часовой стрелке) у нас отрицательные углы (-180,0). Это нормально, но если я хочу вычислить правильное положение часовой стрелки в соответствии с ходом минутной стрелки, я должен перевести эти углы в диапазон 0-360 градусов.

Вот где я обращаюсь с жестами:

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

Вот где я перевожу углы:

    /**
     * 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;
    }

И вот где я знаю, если минутная стрелка начинает новый спин:

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;
        }
    }

Кто-нибудь может мне немного помочь? если кто-нибудь может мне помочь, я обещаю назвать ваше имя моей первой нерожденной дочери... шучу.

1 ответ

Решение

Я обнаружил, где проблема была...

Проблема заключалась в "условиях if" внутри метода newSpin(). Здесь, перед проверкой условий, я перевел углы в исходный формат (от 0 градусов до 180 градусов для двенадцати часов до шести часов по часовой стрелке и от -180 градусов до 0 градусов для шести часов до двенадцати градусов). часов, по часовой стрелке тоже). Таким образом, вместо этого проверьте, запускает ли пользователь новое вращение минутной стрелкой. Он добавляет / вычитает новое вращение каждый раз, когда пользователь проходит через шесть часов вместо двенадцати.

Итак, я исправил это, изменив эти условия и проверив оба угла минутной стрелки, предыдущий и текущий, в формате 360 градусов. Теперь, если предыдущий угол больше 355 градусов, а текущий угол меньше 5 градусов, я добавляю новый спин в mSpinNumber. Аналогично, если предыдущий угол меньше 5 градусов, а текущий угол больше 355 градусов, я вычитаю спин в mSpinNumber. Я также изменил имя метода с newSpin() на CalcuHourHandAngle().

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

Я также избавляюсь от ненужного кода в методе 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;
}

Теперь я могу знать, какой час установил пользователь, потому что я знаю начальную позицию стрелок часов, количество вращений и угол минутной стрелки.

Другие вопросы по тегам