From aac94a8f0e8d78ef95b5d2a6a77fe4e4324a6b4e Mon Sep 17 00:00:00 2001 From: Nishan Date: Fri, 26 May 2023 11:46:42 +0530 Subject: [PATCH] transform origin android --- .../View/ReactNativeStyleAttributes.js | 2 + .../NativeComponent/BaseViewConfig.ios.js | 1 + .../react/uimanager/BaseViewManager.java | 70 ++++++++++++++++++- .../uimanager/BaseViewManagerDelegate.java | 3 + .../uimanager/BaseViewManagerInterface.java | 2 + .../facebook/react/uimanager/ViewProps.java | 2 + 6 files changed, 79 insertions(+), 1 deletion(-) diff --git a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js index 13d8db56a5fe67..d93b08fbdf873d 100644 --- a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -112,6 +112,8 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { */ transform: {process: processTransform}, + transformOrigin: true, + /** * View */ diff --git a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js index bb13443bf44a2d..96fa8a4b1c5fb8 100644 --- a/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js +++ b/packages/react-native/Libraries/NativeComponent/BaseViewConfig.ios.js @@ -193,6 +193,7 @@ const validAttributesForNonEventProps = { overflow: true, shouldRasterizeIOS: true, transform: {diff: require('../Utilities/differ/matricesDiffer')}, + transformOrigin: true, accessibilityRole: true, accessibilityState: true, nativeID: true, 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 a7970346275fd7..aa43be48b8fa57 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 @@ -12,6 +12,7 @@ import android.text.TextUtils; import android.view.View; import android.view.ViewParent; +import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityEvent; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -30,6 +31,8 @@ import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.events.PointerEventHelper; import com.facebook.react.uimanager.util.ReactFindViewUtil; +import com.facebook.react.views.view.ReactViewGroup; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -40,7 +43,32 @@ * provides support for base view properties such as backgroundColor, opacity, etc. */ public abstract class BaseViewManager - extends ViewManager implements BaseViewManagerInterface { + extends ViewManager implements BaseViewManagerInterface, View.OnLayoutChangeListener { + + View.OnLayoutChangeListener layoutListener = null; + String transformOrigin = null; + + @Override + public void onLayoutChange(View v, + int left, + int top, + int right, + int bottom, + int oldLeft, + int oldTop, + int oldRight, + int oldBottom) { + // Old width and height + int oldWidth = oldRight - oldLeft; + int oldHeight = oldBottom - oldTop; + + // Current width and height + int currentWidth = right - left; + int currentHeight = bottom - top; + if (currentHeight != oldHeight || currentWidth != oldWidth) { + setTransformOriginWithViewHeightAndWidth((T) v, currentWidth, currentHeight); + } + } private static final int PERSPECTIVE_ARRAY_INVERTED_CAMERA_DISTANCE_INDEX = 2; private static final float CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER = (float) Math.sqrt(5); @@ -126,6 +154,8 @@ protected T prepareToRecycleView(@NonNull ThemedReactContext reactContext, T vie // Other stuff view.setForeground(null); + view.removeOnLayoutChangeListener(this); + return view; } @@ -148,6 +178,44 @@ public void setTransform(@NonNull T view, @Nullable ReadableArray matrix) { } } + private void setTransformOriginWithViewHeightAndWidth(T view, float width, float height) { + if (transformOrigin == null) { + transformOrigin = "0 0"; + } + + float[] pivotPoints = new float[2]; + // Split the string by space + String[] parts = transformOrigin.split(" "); + + for (int i = 0; i < parts.length; i++) { + boolean isPercent = parts[i].contains("%"); + float value = Float.parseFloat(parts[i].replace("%", "")); + if (isPercent) { + value = (i == 0 ? width : height) * value / 100.0f; + pivotPoints[i] = value; + } else { + pivotPoints[i] = PixelUtil.toPixelFromDIP(value); + } + } + + view.setPivotX(pivotPoints[0]); + view.setPivotY(pivotPoints[1]); + + + view.setRotation(view.getRotation()); + view.setScaleX(view.getScaleX()); + view.setScaleY(view.getScaleX()); + } + + @Override + @ReactProp(name = ViewProps.TRANSFORM_ORIGIN) + public void setTransformOrigin(@NonNull T view, @Nullable String transformOrigin) { + this.transformOrigin = transformOrigin; + // we need to recalculate rotation/scale based new dimensions. Attaches same listener, so looks fine. + view.addOnLayoutChangeListener(this); + setTransformOriginWithViewHeightAndWidth(view, view.getWidth(), view.getHeight()); + } + @Override @ReactProp(name = ViewProps.OPACITY, defaultFloat = 1.f) public void setOpacity(@NonNull T view, float opacity) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerDelegate.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerDelegate.java index e59a1c4da3b80f..341142b560cef2 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerDelegate.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerDelegate.java @@ -121,6 +121,9 @@ public void setProperty(T view, String propName, @Nullable Object value) { case ViewProps.TRANSFORM: mViewManager.setTransform(view, (ReadableArray) value); break; + case ViewProps.TRANSFORM_ORIGIN: + mViewManager.setTransformOrigin(view, (String) value); + break; case ViewProps.TRANSLATE_X: mViewManager.setTranslateX(view, value == null ? 0.0f : ((Double) value).floatValue()); break; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerInterface.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerInterface.java index 5887ff5ba31535..b609d285a8844b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerInterface.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerInterface.java @@ -72,6 +72,8 @@ public interface BaseViewManagerInterface { void setTransform(T view, @Nullable ReadableArray matrix); + void setTransformOrigin(T view, @Nullable String transformOrigin); + void setTranslateX(T view, float translateX); void setTranslateY(T view, float translateY); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java index cc9f7178e65919..fa6eae38a49771 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java @@ -151,6 +151,8 @@ public class ViewProps { public static final String ON_LAYOUT = "onLayout"; public static final String TRANSFORM = "transform"; + + public static final String TRANSFORM_ORIGIN = "transformOrigin"; public static final String ELEVATION = "elevation"; public static final String SHADOW_COLOR = "shadowColor"; public static final String Z_INDEX = "zIndex";