From 51f94e3318368af9f249a23dc313e12d9537282f Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Mon, 13 Apr 2026 23:14:07 -0400 Subject: [PATCH] fix(android): opacity not animating when combined with rotation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setBackfaceVisibilityDependantOpacity() resets alpha to 1.0 every frame during rotation animations, overriding animated opacity. Skip the backface check when MASK_OPACITY is set — the opacity animator handles alpha directly in that case. --- android/src/main/java/com/ease/EaseView.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/ease/EaseView.kt b/android/src/main/java/com/ease/EaseView.kt index e599383..be32c29 100644 --- a/android/src/main/java/com/ease/EaseView.kt +++ b/android/src/main/java/com/ease/EaseView.kt @@ -446,8 +446,10 @@ class EaseView(context: Context) : ReactViewGroup(context) { } // Update backface visibility after setting initial rotation values. + // Skip when opacity is animated — backface check resets alpha. // https://github.com/facebook/react-native/blob/a98aa814/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt#L967-L985 - if (mask and (MASK_ROTATE or MASK_ROTATE_X or MASK_ROTATE_Y) != 0) { + if (mask and (MASK_ROTATE or MASK_ROTATE_X or MASK_ROTATE_Y) != 0 && + mask and MASK_OPACITY == 0) { setBackfaceVisibilityDependantOpacity() } } else if (allTransitionsNone()) { @@ -820,7 +822,10 @@ class EaseView(context: Context) : ReactViewGroup(context) { val batchId = animationBatchId pendingBatchAnimationCount++ - val needsBackfaceUpdate = propertyName in isRotationProperty + // Only update backface visibility when opacity is NOT animated — the backface + // check resets alpha, which would clobber the animated opacity value. + val needsBackfaceUpdate = propertyName in isRotationProperty && + (animatedProperties and MASK_OPACITY == 0) val animator = ObjectAnimator.ofFloat(this, propertyName, fromValue, toValue).apply { duration = config.duration.toLong() @@ -880,9 +885,10 @@ class EaseView(context: Context) : ReactViewGroup(context) { val batchId = animationBatchId pendingBatchAnimationCount++ - val needsBackfaceUpdate = viewProperty == DynamicAnimation.ROTATION || + val needsBackfaceUpdate = (viewProperty == DynamicAnimation.ROTATION || viewProperty == DynamicAnimation.ROTATION_X || - viewProperty == DynamicAnimation.ROTATION_Y + viewProperty == DynamicAnimation.ROTATION_Y) && + (animatedProperties and MASK_OPACITY == 0) val dampingRatio = (config.damping / (2.0f * sqrt(config.stiffness * config.mass))) .coerceAtLeast(0.01f)