feat(android): percentage support in translate (#43193)

Summary:
This PR adds percentage support in translate properties for android. Isolating this PR for easier reviews.

## Changelog:
[Android] [ADDED] - Percentage support in translate
<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests

Pull Request resolved: https://github.com/facebook/react-native/pull/43193

Test Plan:
- Checkout TransformExample.js -> Translate percentage example.
- Added a simple test in `processTransform-test.js`. The regex is not perfect (values like 20px%, 20%px will pass, can be improved, let me know!)

Related PRs - https://github.com/facebook/react-native/pull/43191, https://github.com/facebook/react-native/pull/43192

Reviewed By: joevilches

Differential Revision: D57723216

Pulled By: NickGerleman

fbshipit-source-id: c9da007678341b62745df858f043821bcc662a98
This commit is contained in:
Nishan
2024-05-24 04:50:41 -07:00
committed by Facebook GitHub Bot
parent 4294b2446a
commit c13790ff1d
2 changed files with 47 additions and 15 deletions
@@ -148,7 +148,7 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
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 abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
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 abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
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 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
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);
}
@@ -103,14 +103,36 @@ public class TransformHelper {
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,20 @@ public class TransformHelper {
}
}
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)) {