-
Notifications
You must be signed in to change notification settings - Fork 24.3k
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
feat: android transform origin #38558
Conversation
@@ -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 { |
There was a problem hiding this comment.
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.
...es/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java
Outdated
Show resolved
Hide resolved
if (offsets != null) { | ||
MatrixMathHelper.resetIdentityMatrix(helperMatrix); | ||
MatrixMathHelper.applyTranslate3D(helperMatrix, offsets[0], offsets[1], offsets[2]); | ||
MatrixMathHelper.multiplyInto(result, result, helperMatrix); |
There was a problem hiding this comment.
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.
Base commit: 0b6e9bf |
@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) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
...es/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java
Outdated
Show resolved
Hide resolved
…nsform origin is not present
...es/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java
Outdated
Show resolved
Hide resolved
@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); |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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!
This should be rebased on #38559 so we can land them in that order. |
@javache has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
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
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
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
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
.