Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: android transform origin #38558

Conversation

intergalacticspacehighway
Copy link
Contributor

Summary:

This PR adds transform-origin support for android to make it easier to review. #37606 (review) by @javache. I'll answer feedback from @javache below.

Changelog:

[Android] [ADDED] - Transform origin

Test Plan:

Run iOS RNTester app in old architecture and test transform-origin example in TransformExample.js.

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. labels Jul 23, 2023
@@ -40,7 +40,7 @@
* provides support for base view properties such as backgroundColor, opacity, etc.
*/
public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode>
extends ViewManager<T, C> implements BaseViewManagerInterface<T> {
extends ViewManager<T, C> implements BaseViewManagerInterface<T>, View.OnLayoutChangeListener {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

layout on a view is updated here. We can use onSizeChanged callback from ReactViewGroup instead of a listener here but we'll have to move the transform logic there and might need refactor as MatrixHelper class is in uimanager package and has some fields private. Also do some type cast here to call ReactViewGroup's set transform.

if (offsets != null) {
MatrixMathHelper.resetIdentityMatrix(helperMatrix);
MatrixMathHelper.applyTranslate3D(helperMatrix, offsets[0], offsets[1], offsets[2]);
MatrixMathHelper.multiplyInto(result, result, helperMatrix);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

answering #37606 (comment)
Multiply is required because the operation is order dependent. i.e. we need to multiply the translate operations or else the view is not translated to the transform-origin before applying other transforms 😅

We also reset the helperMatrix which behaves weird when there are multiple view transform animations running. I think it's reusing the instance between different animations.

@analysis-bot
Copy link

analysis-bot commented Jul 23, 2023

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 8,832,169 -130,625
android hermes armeabi-v7a 8142161 n/a
android hermes x86 9337701 n/a
android hermes x86_64 9180636 n/a
android jsc arm64-v8a 9,450,208 -103,737
android jsc armeabi-v7a 8632229 n/a
android jsc x86 9533110 n/a
android jsc x86_64 9776308 n/a

Base commit: 0b6e9bf
Branch: main

@intergalacticspacehighway intergalacticspacehighway changed the title feat(android): transform origin feat: android transform origin Jul 27, 2023
@facebook-github-bot
Copy link
Contributor

@rozele has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@@ -45,7 +45,7 @@ private static double convertToRadians(ReadableMap transformMap, String key) {
return inRadians ? value : MatrixMathHelper.degreesToRadians(value);
}

public static void processTransform(ReadableArray transforms, double[] result) {
public static void processTransform(ReadableArray transforms, double[] result, float viewWidth, float viewHeight, ReadableArray transformOrigin) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like TransformHelper.processTransform is exposed publicly, and the API was previously being used by react-native-svg. So the change is breaking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it. Added an overloaded method to make it backward compatible.

switch (valueLower) {
case 'left':
case 'right': {
invariant(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's subjective, but there was some discussion within the team before on whether we should be permissive of invalid styles during development. E.g. add a warning, instead of throwing an exception. I think we changed some other to be more permissive and just warn and no-op, since unhandled exception is disruptive during development/live reload, but I could see both ways.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc - @jacobp100 need to handle this in all PRs. wdyt? maybe use console.warn?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I can make changes to this. If you let me know what way you want to go I'll update it in my PR (#38626)

@@ -129,6 +132,33 @@ protected T prepareToRecycleView(@NonNull ThemedReactContext reactContext, T vie
return view;
}

@Override
public void onLayoutChange(View v,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: It seems potentially error prone that this is only called when a transform is present. I.e. I could imagine someone adding code here, not realizing that it isn't always called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, just didn't want to attach a listener if it was not needed. Should we write a comment maybe?

// Currently, the onLayout listener is only attached when transform-origin prop is being used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also removed the listener when transform-origin is null.

Comment on lines 173 to 195
@ReactProp(name = ViewProps.TRANSFORM)
public void setTransform(@NonNull T view, @Nullable ReadableArray matrix) {
view.setTag(R.id.transform, matrix);
if (matrix == null) {
resetTransformProperty(view);
} else {
setTransformProperty(view, matrix);
ReadableArray transformOrigin = (ReadableArray) view.getTag(R.id.transform_origin);
setTransformProperty(view, matrix, transformOrigin);
}
}

@Override
@ReactProp(name = ViewProps.TRANSFORM_ORIGIN)
public void setTransformOrigin(@NonNull T view, @Nullable ReadableArray transformOrigin) {
view.setTag(R.id.transform_origin, transformOrigin);
ReadableArray transformMatrix = (ReadableArray) view.getTag(R.id.transform);
if (transformMatrix != null) {
setTransformProperty(view, transformMatrix, transformOrigin);
}
if (transformOrigin != null) {
view.addOnLayoutChangeListener(this);
} else {
view.removeOnLayoutChangeListener(this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the best solution is, but because setters are called in series, we will be calculating the transform twice, once after setTransform and again after setTransformOrigin.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, i had this concern. I think we can call in onAfterUpdateTransaction when both values are set. While testing I noticed that onAfterUpdateTransaction is not called for animating values. So I guess we still call it in setters but use onAfterUpdateTransaction for the initial mount.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@javache pushed an optimization. This works with animated values as well as fabric. onAfterUpdateTransaction is triggered reliably. I did something wrong in my earlier observations. I don't like this id approach but can't use instance variable as View manager can manage multiple views. Another approach would be to move the transform stuff in RootViewGroup, but that will require type casting the generic view in Manager and will need to move some files. Let me know wyt! Also thanks for the quick reviews and sorry to disturb during your parental leaves!

@javache
Copy link
Member

javache commented Aug 24, 2023

This should be rebased on #38559 so we can land them in that order.

@facebook-github-bot
Copy link
Contributor

@javache has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

javache pushed a commit to javache/react-native that referenced this pull request Sep 1, 2023
Summary:
This PR adds transform-origin support for android to make it easier to review. facebook#37606 (review) by javache. I'll answer feedback from javache below.

## Changelog:
[Android] [ADDED] - Transform origin
<!-- 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: facebook#38558

Test Plan: Run iOS RNTester app in old architecture and test transform-origin example in `TransformExample.js`.

Differential Revision: D48528339

Pulled By: javache

fbshipit-source-id: 09e0c9ef569b7e9131da2f6efa9ba057aa98ff82
javache pushed a commit to javache/react-native that referenced this pull request Sep 1, 2023
Summary:
Adds transform-origin for old arch iOS

See also intergalacticspacehighway's work for iOS Fabric and Android:-

- facebook#38559
- facebook#38558

## Changelog:

[IOS] [ADDED] - Added support for transform-origin on old arch

Pull Request resolved: facebook#38626

Test Plan: See RN tester

Differential Revision: D48528353

Pulled By: javache

fbshipit-source-id: 0189f374c9556b6593b3d72d7503b9cf166378c2
facebook-github-bot pushed a commit that referenced this pull request Sep 1, 2023
Summary:
Adds transform-origin for old arch iOS

See also intergalacticspacehighway's work for iOS Fabric and Android:-

- #38559
- #38558

## Changelog:

[IOS] [ADDED] - Added support for transform-origin on old arch

Pull Request resolved: #38626

Test Plan: See RN tester

Reviewed By: NickGerleman

Differential Revision: D48528353

Pulled By: javache

fbshipit-source-id: 09592411e26484d81a999a7e601eff751ca7ae0b
@facebook-github-bot facebook-github-bot added the Merged This PR has been merged. label Sep 1, 2023
@facebook-github-bot
Copy link
Contributor

@javache merged this pull request in 9e68599.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants