如何监听Wear OS表盘激活/退居后台事件实现切换动画?
实现三星Watch6原生表盘的平滑切换动画
一、监听表盘激活事件(从选择界面切换到实际表盘)
在自定义的WatchFaceService.Engine子类中,重写onVisibilityChanged方法。当用户从表盘选择界面切换到该表盘时,visibility会变为View.VISIBLE,此时可触发指针从预览固定位置过渡到当前实际时间的动画:
override fun onVisibilityChanged(visibility: Int) { super.onVisibilityChanged(visibility) if (visibility == View.VISIBLE) { // 触发从预览位置到实际时间的平滑过渡动画 startTransitionToActualTime() } }
二、监听表盘即将进入预览状态(切换出表盘到选择界面)
重写onPreviewModeChanged方法,当系统进入表盘预览模式(用户打开表盘选择界面)时,isPreview会变为true,此时触发指针从实际时间过渡到预览固定位置的动画:
override fun onPreviewModeChanged(isPreview: Boolean) { super.onPreviewModeChanged(isPreview) if (isPreview) { // 触发从实际时间到预览固定位置的快速过渡动画 startTransitionToPreviewPosition() } }
三、实现指针过渡动画
使用ValueAnimator计算指针的角度变化,实现平滑过渡:
private fun startTransitionToActualTime() { // 预览图固定位置角度(需与表盘选择界面的预览图匹配) val previewHourAngle = 90f val previewMinuteAngle = 0f // 计算当前实际时间对应的指针角度 val actualHourAngle = calculateHourAngle(System.currentTimeMillis()) val actualMinuteAngle = calculateMinuteAngle(System.currentTimeMillis()) // 时针过渡动画 ValueAnimator.ofFloat(previewHourAngle, actualHourAngle).apply { duration = 500 addUpdateListener { animation -> hourHandAngle = animation.animatedValue as Float invalidate() } start() } // 分针过渡动画 ValueAnimator.ofFloat(previewMinuteAngle, actualMinuteAngle).apply { duration = 500 addUpdateListener { animation -> minuteHandAngle = animation.animatedValue as Float invalidate() } start() } } private fun startTransitionToPreviewPosition() { val previewHourAngle = 90f val previewMinuteAngle = 0f ValueAnimator.ofFloat(hourHandAngle, previewHourAngle).apply { duration = 300 addUpdateListener { animation -> hourHandAngle = animation.animatedValue as Float invalidate() } start() } ValueAnimator.ofFloat(minuteHandAngle, previewMinuteAngle).apply { duration = 300 addUpdateListener { animation -> minuteHandAngle = animation.animatedValue as Float invalidate() } start() } } // 计算时针角度 private fun calculateHourAngle(timestamp: Long): Float { val calendar = Calendar.getInstance().apply { timeInMillis = timestamp } val hours = calendar.get(Calendar.HOUR_OF_DAY) % 12 val minutes = calendar.get(Calendar.MINUTE) return (hours * 30 + minutes * 0.5).toFloat() } // 计算分针角度 private fun calculateMinuteAngle(timestamp: Long): Float { val calendar = Calendar.getInstance().apply { timeInMillis = timestamp } val minutes = calendar.get(Calendar.MINUTE) return minutes * 6f }
注意事项
- 预览固定位置的角度必须与表盘选择界面的预览图完全匹配,否则动画衔接会出现断层。
- 在
onDraw方法中,需根据实时更新的hourHandAngle、minuteHandAngle变量绘制指针,确保动画过程中界面实时刷新。 - 若需适配熄屏/亮屏场景,可结合
onEnterAmbient和onExitAmbient方法调整动画逻辑。
内容的提问来源于stack exchange,提问作者AZX
相关产品推荐
相关产品推荐

