Skip to content

Commit 1292480

Browse files
NickGerlemanpull[bot]
authored andcommitted
Port "setAndroidLayoutDirection" to Paper (#45422)
Summary: Pull Request resolved: #45422 When `ReactNativeFeatureFlags.setAndroidLayoutDirection()` is set, we assume in components like ReactHorizontalScrolView that the Yoga contextual layout direction has been set on the underlying component, and skip using I18nManager global direction. These native views are also used in Paper, so we need to make the change there as well to avoid regressions. This change mechanically ports the change from Fabric to Paper, at the same layer as used in Fabric (applying ShadowNode layout to the Android view tree). Changelog: [Internal] Reviewed By: rshest Differential Revision: D59708408 fbshipit-source-id: 52d6fa80c102250eae7ccccedd7184569f6a727f
1 parent 26df440 commit 1292480

File tree

6 files changed

+85
-8
lines changed

6 files changed

+85
-8
lines changed

packages/react-native/ReactAndroid/api/ReactAndroid.api

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4309,7 +4309,8 @@ public class com/facebook/react/uimanager/NativeViewHierarchyManager {
43094309
public fun setJSResponder (IIZ)V
43104310
public fun setLayoutAnimationEnabled (Z)V
43114311
public fun updateInstanceHandle (IJ)V
4312-
public fun updateLayout (IIIIII)V
4312+
public fun updateLayout (IIIII)V
4313+
public fun updateLayout (IIIIIILcom/facebook/yoga/YogaDirection;)V
43134314
public fun updateProperties (ILcom/facebook/react/uimanager/ReactStylesDiffMap;)V
43144315
public fun updateViewExtraData (ILjava/lang/Object;)V
43154316
}
@@ -5206,6 +5207,7 @@ public class com/facebook/react/uimanager/UIViewOperationQueue {
52065207
public fun enqueueUpdateExtraData (ILjava/lang/Object;)V
52075208
public fun enqueueUpdateInstanceHandle (IJ)V
52085209
public fun enqueueUpdateLayout (IIIIII)V
5210+
public fun enqueueUpdateLayout (IIIIIILcom/facebook/yoga/YogaDirection;)V
52095211
public fun enqueueUpdateProperties (ILjava/lang/String;Lcom/facebook/react/uimanager/ReactStylesDiffMap;)V
52105212
public fun getProfiledBatchPerfCounters ()Ljava/util/Map;
52115213
public fun isEmpty ()Z
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.uimanager
9+
10+
import android.view.View
11+
import com.facebook.yoga.YogaDirection
12+
13+
internal object LayoutDirectionUtil {
14+
@JvmStatic
15+
public fun toAndroidFromYoga(direction: YogaDirection): Int =
16+
when (direction) {
17+
YogaDirection.LTR -> View.LAYOUT_DIRECTION_LTR
18+
YogaDirection.RTL -> View.LAYOUT_DIRECTION_RTL
19+
else -> View.LAYOUT_DIRECTION_INHERIT
20+
}
21+
22+
@JvmStatic
23+
public fun toYogaFromAndroid(direction: Int): YogaDirection =
24+
when (direction) {
25+
View.LAYOUT_DIRECTION_LTR -> YogaDirection.LTR
26+
View.LAYOUT_DIRECTION_RTL -> YogaDirection.RTL
27+
else -> YogaDirection.INHERIT
28+
}
29+
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@
2727
import com.facebook.react.bridge.SoftAssertions;
2828
import com.facebook.react.bridge.UiThreadUtil;
2929
import com.facebook.react.common.build.ReactBuildConfig;
30+
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
3031
import com.facebook.react.touch.JSResponderHandler;
3132
import com.facebook.react.uimanager.layoutanimation.LayoutAnimationController;
3233
import com.facebook.react.uimanager.layoutanimation.LayoutAnimationListener;
3334
import com.facebook.systrace.Systrace;
3435
import com.facebook.systrace.SystraceMessage;
36+
import com.facebook.yoga.YogaDirection;
3537
import java.util.HashMap;
3638
import java.util.HashSet;
3739
import java.util.Set;
@@ -153,8 +155,17 @@ public synchronized void updateViewExtraData(int tag, Object extraData) {
153155
viewManager.updateExtraData(viewToUpdate, extraData);
154156
}
155157

158+
/**
159+
* @deprecated Please use {@link #updateLayout(int tag, int x, int y, int width, int height,
160+
* YogaDirection layoutDirection)} instead.
161+
*/
162+
@Deprecated
163+
public void updateLayout(int tag, int x, int y, int width, int height) {
164+
updateLayout(tag, tag, x, y, width, height, YogaDirection.INHERIT);
165+
}
166+
156167
public synchronized void updateLayout(
157-
int parentTag, int tag, int x, int y, int width, int height) {
168+
int parentTag, int tag, int x, int y, int width, int height, YogaDirection layoutDirection) {
158169
if (DEBUG_MODE) {
159170
FLog.d(TAG, "updateLayout[%d]->[%d]: %d %d %d %d", tag, parentTag, x, y, width, height);
160171
}
@@ -167,6 +178,10 @@ public synchronized void updateLayout(
167178
try {
168179
View viewToUpdate = resolveView(tag);
169180

181+
if (ReactNativeFeatureFlags.setAndroidLayoutDirection()) {
182+
viewToUpdate.setLayoutDirection(LayoutDirectionUtil.toAndroidFromYoga(layoutDirection));
183+
}
184+
170185
// Even though we have exact dimensions, we still call measure because some platform views
171186
// (e.g.
172187
// Switch) assume that method will always be called before onLayout and onDraw. They use it to

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,8 @@ public void handleUpdateLayout(ReactShadowNode node) {
206206
node.getScreenX(),
207207
node.getScreenY(),
208208
node.getScreenWidth(),
209-
node.getScreenHeight());
209+
node.getScreenHeight(),
210+
node.getLayoutDirection());
210211
return;
211212
}
212213

@@ -370,7 +371,8 @@ private void applyLayoutRecursive(ReactShadowNode toUpdate, int x, int y) {
370371
x,
371372
y,
372373
toUpdate.getScreenWidth(),
373-
toUpdate.getScreenHeight());
374+
toUpdate.getScreenHeight(),
375+
toUpdate.getLayoutDirection());
374376
return;
375377
}
376378

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,8 @@ public void dispatchUpdates(
406406
getScreenX(),
407407
getScreenY(),
408408
getScreenWidth(),
409-
getScreenHeight());
409+
getScreenHeight(),
410+
getLayoutDirection());
410411
}
411412
}
412413
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
3131
import com.facebook.systrace.Systrace;
3232
import com.facebook.systrace.SystraceMessage;
33+
import com.facebook.yoga.YogaDirection;
3334
import java.util.ArrayDeque;
3435
import java.util.ArrayList;
3536
import java.util.HashMap;
@@ -118,21 +119,31 @@ public void execute() {
118119
private final class UpdateLayoutOperation extends ViewOperation {
119120

120121
private final int mParentTag, mX, mY, mWidth, mHeight;
122+
private final YogaDirection mLayoutDirection;
121123

122-
public UpdateLayoutOperation(int parentTag, int tag, int x, int y, int width, int height) {
124+
public UpdateLayoutOperation(
125+
int parentTag,
126+
int tag,
127+
int x,
128+
int y,
129+
int width,
130+
int height,
131+
YogaDirection layoutDirection) {
123132
super(tag);
124133
mParentTag = parentTag;
125134
mX = x;
126135
mY = y;
127136
mWidth = width;
128137
mHeight = height;
138+
mLayoutDirection = layoutDirection;
129139
Systrace.startAsyncFlow(Systrace.TRACE_TAG_REACT_VIEW, "updateLayout", mTag);
130140
}
131141

132142
@Override
133143
public void execute() {
134144
Systrace.endAsyncFlow(Systrace.TRACE_TAG_REACT_VIEW, "updateLayout", mTag);
135-
mNativeViewHierarchyManager.updateLayout(mParentTag, mTag, mX, mY, mWidth, mHeight);
145+
mNativeViewHierarchyManager.updateLayout(
146+
mParentTag, mTag, mX, mY, mWidth, mHeight, mLayoutDirection);
136147
}
137148
}
138149

@@ -698,9 +709,26 @@ public void enqueueUpdateProperties(int reactTag, String className, ReactStylesD
698709
mOperations.add(new UpdatePropertiesOperation(reactTag, props));
699710
}
700711

712+
/**
713+
* @deprecated Use {@link #enqueueUpdateLayout(int, int, int, int, int, int, YogaDirection)}
714+
* instead.
715+
*/
716+
@Deprecated
701717
public void enqueueUpdateLayout(
702718
int parentTag, int reactTag, int x, int y, int width, int height) {
703-
mOperations.add(new UpdateLayoutOperation(parentTag, reactTag, x, y, width, height));
719+
enqueueUpdateLayout(parentTag, reactTag, x, y, width, height, YogaDirection.INHERIT);
720+
}
721+
722+
public void enqueueUpdateLayout(
723+
int parentTag,
724+
int reactTag,
725+
int x,
726+
int y,
727+
int width,
728+
int height,
729+
YogaDirection layoutDirection) {
730+
mOperations.add(
731+
new UpdateLayoutOperation(parentTag, reactTag, x, y, width, height, layoutDirection));
704732
}
705733

706734
public void enqueueManageChildren(

0 commit comments

Comments
 (0)