diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index 4a28227d5ce026..4012c71fe19b81 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -148,7 +148,7 @@ protected T prepareToRecycleView(@NonNull ThemedReactContext reactContext, T vie return view; } - // Currently. onLayout listener is only attached when transform origin prop is being used. + // Currently, layout listener is only attached when transform or transformOrigin is set. @Override public void onLayoutChange( View v, @@ -170,9 +170,9 @@ public void onLayoutChange( if ((currentHeight != oldHeight || currentWidth != oldWidth)) { ReadableArray transformOrigin = (ReadableArray) v.getTag(R.id.transform_origin); - ReadableArray transformMatrix = (ReadableArray) v.getTag(R.id.transform); - if (transformMatrix != null && transformOrigin != null) { - setTransformProperty((T) v, transformMatrix, transformOrigin); + ReadableArray transforms = (ReadableArray) v.getTag(R.id.transform); + if (transforms != null || transformOrigin != null) { + setTransformProperty((T) v, transforms, transformOrigin); } } } @@ -204,11 +204,6 @@ public void setTransform(@NonNull T view, @Nullable ReadableArray matrix) { public void setTransformOrigin(@NonNull T view, @Nullable ReadableArray transformOrigin) { view.setTag(R.id.transform_origin, transformOrigin); view.setTag(R.id.invalidate_transform, true); - if (transformOrigin != null) { - view.addOnLayoutChangeListener(this); - } else { - view.removeOnLayoutChangeListener(this); - } } @Override @@ -623,9 +618,10 @@ protected void onAfterUpdateTransaction(@NonNull T view) { Boolean invalidateTransform = (Boolean) view.getTag(R.id.invalidate_transform); if (invalidateTransform != null && invalidateTransform) { + view.addOnLayoutChangeListener(this); ReadableArray transformOrigin = (ReadableArray) view.getTag(R.id.transform_origin); - ReadableArray transformMatrix = (ReadableArray) view.getTag(R.id.transform); - setTransformProperty(view, transformMatrix, transformOrigin); + ReadableArray transforms = (ReadableArray) view.getTag(R.id.transform); + setTransformProperty(view, transforms, transformOrigin); view.setTag(R.id.invalidate_transform, false); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java index 5a5a9ddaa92750..547b5017dbe4c2 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java @@ -103,14 +103,36 @@ public static void processTransform( MatrixMathHelper.applyScaleY(helperMatrix, transform.getDouble(transformType)); } else if ("translate".equals(transformType)) { ReadableArray value = transform.getArray(transformType); - double x = value.getDouble(0); - double y = value.getDouble(1); + double x = 0; + if (value.getType(0) == ReadableType.String) { + x = parseTranslateValue(value.getString(0), viewWidth); + } else { + x = value.getDouble(0); + } + double y = 0; + if (value.getType(1) == ReadableType.String) { + y = parseTranslateValue(value.getString(1), viewHeight); + } else { + y = value.getDouble(1); + } double z = value.size() > 2 ? value.getDouble(2) : 0d; MatrixMathHelper.applyTranslate3D(helperMatrix, x, y, z); } else if ("translateX".equals(transformType)) { - MatrixMathHelper.applyTranslate2D(helperMatrix, transform.getDouble(transformType), 0d); + double translateValue = 0; + if (transform.getType(transformType) == ReadableType.String) { + translateValue = parseTranslateValue(transform.getString(transformType), viewWidth); + } else { + translateValue = transform.getDouble(transformType); + } + MatrixMathHelper.applyTranslate2D(helperMatrix, translateValue, 0d); } else if ("translateY".equals(transformType)) { - MatrixMathHelper.applyTranslate2D(helperMatrix, 0d, transform.getDouble(transformType)); + double translateValue = 0; + if (transform.getType(transformType) == ReadableType.String) { + translateValue = parseTranslateValue(transform.getString(transformType), viewHeight); + } else { + translateValue = transform.getDouble(transformType); + } + MatrixMathHelper.applyTranslate2D(helperMatrix, 0d, translateValue); } else if ("skewX".equals(transformType)) { MatrixMathHelper.applySkewX(helperMatrix, convertToRadians(transform, transformType)); } else if ("skewY".equals(transformType)) { @@ -130,6 +152,19 @@ public static void processTransform( } } + private static double parseTranslateValue(String stringValue, double dimension) { + try { + if (stringValue.endsWith("%")) { + double percentage = Double.parseDouble(stringValue.substring(0, stringValue.length() - 1)); + return percentage * dimension / 100.0; + } else { + return Double.parseDouble(stringValue); + } + } catch (NumberFormatException e) { + FLog.w(ReactConstants.TAG, "Invalid translate value: " + stringValue); + } + return 0; + } private static float[] getTranslateForTransformOrigin( float viewWidth, float viewHeight, ReadableArray transformOrigin) { if (transformOrigin == null || (viewHeight == 0 && viewWidth == 0)) {