Pablo Darde
Pablo Darde

Reputation: 6402

How to rotate a second's hand watch five times in a second in Wear OS?

I'm developing a watch face and want to rotate the second's hand 1.2 degrees in 1/5 of a second.

Why these numbers?

1) 360 degrees / 60 seconds = 6 degress per second

2) 6 degrees / 5 = 1.2 degrees (rotates 1.2 degrees in a fifth of a second).

Below is the normal rotation (6 degress in a second).

enter image description here

The image above spends one second to rotate 6 degrees.

My question is: How to spends one fifth of a second to rotate 1.2 degress?

This is my code:

private void drawClassicSecondsHand(Canvas canvas) {

    final int seconds = (mCalendar.get(Calendar.SECOND));
    final float secondsRotation = seconds * 6;

    float originRadius = complicationHandBitmap.getWidth() / 2f;

    float secondsAreaCenterX = mCenterX - (float) (mCenterX * 0.45);
    canvas.rotate(secondsRotation, secondsAreaCenterX, mCenterY);
    classicSecondsComplication.draw(
            canvas,
            secondsAreaCenterX,
            mCenterY,
            classicComplicationRadius,
            complicationHandBitmap,
            originRadius);
}

The above method is called in the onDraw method of my watch face service.

public void onDraw(Canvas canvas, Rect bounds) {

   ...
   drawClassicSecondsHand(Canvas canvas);
}

Upvotes: 1

Views: 567

Answers (2)

TofferJ
TofferJ

Reputation: 4784

I'm not sure where your onDraw method is called from right now, but updating continuously is not good from a battery life point of view.

If you create a new project in Android Studio and select Wear OS and the analog watch face template you'll see a better way to do it. At the very bottom they set up a message handler that will trigger redraws of the watch face at a specific interval (in interactive mode).

/**
 * Handle updating the time periodically in interactive mode.
 */
private void handleUpdateTimeMessage() {
    invalidate();
    if (shouldTimerBeRunning()) {
        long timeMs = System.currentTimeMillis();
        long delayMs = INTERACTIVE_UPDATE_RATE_MS
                - (timeMs % INTERACTIVE_UPDATE_RATE_MS);
        mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
    }
}

(There are more parts to it than the snippet above, but everything is in the sample watch face.)

In this example the INTERACTIVE_UPDATE_RATE_MS is set to a second. All you have to do is set it to 200ms, and your watch face will update five times per second. Rotate the canvas 1.2 degrees each time and you'll have the desired second hand movement.

Upvotes: 2

Andreas
Andreas

Reputation: 159106

You need to include the millisecond in the calculation.

You should also get rid of excessive parentheses and the unnecessary cast.

final int seconds = mCalendar.get(Calendar.SECOND);
final int millis = mCalendar.get(Calendar.MILLISECOND);
final float secondsRotation = (seconds + millis / 1000f) * 6;

The f at the end of the 1000f literal makes it a float, preventing integer math truncation issues.
That means millis is promoted to float, so the result of division is float.
That in turn promotes seconds to float, so the result of addition is float.
That in turn promotes 6 to float, so the result of multiplication is float.
There is then no need to cast the result.

Upvotes: 2

Related Questions