mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Top-down onLayout events (#39644)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/39644 This makes Android Paper/Classic renderer fire `onLayout` events top down, like in Fabric/new Architecture. This gives a much more sane model for using layout events to calculate bottom/right-edge insets. I was under the impression that Paper in general was bottom-up, but it turns out that is only true for Android and Windows (iOS seems totally deterministic). This is a behavior change, but to my knowledge was never hit during the Fabric migration, and any JS code already written for both Android and iOS cannot make assumptions here anyways. Changelog: [General][Changed] - Make layout events top-down on Android classic renderer Reviewed By: mdvacca Differential Revision: D49627996 fbshipit-source-id: 29964b421dd420681d45348c7db16f211a6c087f
This commit is contained in:
committed by
Facebook GitHub Bot
parent
ea88338d75
commit
25478321f9
+2
-2
@@ -123,9 +123,9 @@ public interface ReactShadowNode<T extends ReactShadowNode> {
|
||||
*/
|
||||
void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue);
|
||||
|
||||
/** @return true if layout (position or dimensions) changed, false otherwise. */
|
||||
/* package */ boolean dispatchUpdatesWillChangeLayout(float absoluteX, float absoluteY);
|
||||
|
||||
/* package */ boolean dispatchUpdates(
|
||||
/* package */ void dispatchUpdates(
|
||||
float absoluteX,
|
||||
float absoluteY,
|
||||
UIViewOperationQueue uiViewOperationQueue,
|
||||
|
||||
+25
-6
@@ -337,9 +337,32 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
|
||||
@Override
|
||||
public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {}
|
||||
|
||||
/** @return true if layout (position or dimensions) changed, false otherwise. */
|
||||
@Override
|
||||
public boolean dispatchUpdates(
|
||||
public boolean dispatchUpdatesWillChangeLayout(float absoluteX, float absoluteY) {
|
||||
if (!hasNewLayout()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float layoutX = getLayoutX();
|
||||
float layoutY = getLayoutY();
|
||||
int newAbsoluteLeft = Math.round(absoluteX + layoutX);
|
||||
int newAbsoluteTop = Math.round(absoluteY + layoutY);
|
||||
int newAbsoluteRight = Math.round(absoluteX + layoutX + getLayoutWidth());
|
||||
int newAbsoluteBottom = Math.round(absoluteY + layoutY + getLayoutHeight());
|
||||
|
||||
int newScreenX = Math.round(layoutX);
|
||||
int newScreenY = Math.round(layoutY);
|
||||
int newScreenWidth = newAbsoluteRight - newAbsoluteLeft;
|
||||
int newScreenHeight = newAbsoluteBottom - newAbsoluteTop;
|
||||
|
||||
return newScreenX != mScreenX
|
||||
|| newScreenY != mScreenY
|
||||
|| newScreenWidth != mScreenWidth
|
||||
|| newScreenHeight != mScreenHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchUpdates(
|
||||
float absoluteX,
|
||||
float absoluteY,
|
||||
UIViewOperationQueue uiViewOperationQueue,
|
||||
@@ -386,10 +409,6 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
|
||||
getScreenHeight());
|
||||
}
|
||||
}
|
||||
|
||||
return layoutHasChanged;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+32
-22
@@ -29,7 +29,9 @@ import com.facebook.systrace.Systrace;
|
||||
import com.facebook.systrace.SystraceMessage;
|
||||
import com.facebook.yoga.YogaConstants;
|
||||
import com.facebook.yoga.YogaDirection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -665,7 +667,20 @@ public class UIImplementation {
|
||||
.arg("rootTag", cssRoot.getReactTag())
|
||||
.flush();
|
||||
try {
|
||||
applyUpdatesRecursive(cssRoot, 0f, 0f);
|
||||
List<ReactShadowNode> onLayoutNodes = new ArrayList<>();
|
||||
applyUpdatesRecursive(cssRoot, 0f, 0f, onLayoutNodes);
|
||||
|
||||
for (ReactShadowNode node : onLayoutNodes) {
|
||||
mEventDispatcher.dispatchEvent(
|
||||
OnLayoutEvent.obtain(
|
||||
-1, /* surfaceId not used in classic renderer */
|
||||
node.getReactTag(),
|
||||
node.getScreenX(),
|
||||
node.getScreenY(),
|
||||
node.getScreenWidth(),
|
||||
node.getScreenHeight()));
|
||||
}
|
||||
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
@@ -951,39 +966,34 @@ public class UIImplementation {
|
||||
}
|
||||
}
|
||||
|
||||
protected void applyUpdatesRecursive(ReactShadowNode cssNode, float absoluteX, float absoluteY) {
|
||||
protected void applyUpdatesRecursive(
|
||||
ReactShadowNode cssNode,
|
||||
float absoluteX,
|
||||
float absoluteY,
|
||||
List<ReactShadowNode> onLayoutNodes) {
|
||||
if (!cssNode.hasUpdates()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cssNode.dispatchUpdatesWillChangeLayout(absoluteX, absoluteY)
|
||||
&& cssNode.shouldNotifyOnLayout()
|
||||
&& !mShadowNodeRegistry.isRootNode(cssNode.getReactTag())) {
|
||||
onLayoutNodes.add(cssNode);
|
||||
}
|
||||
|
||||
Iterable<? extends ReactShadowNode> cssChildren = cssNode.calculateLayoutOnChildren();
|
||||
if (cssChildren != null) {
|
||||
for (ReactShadowNode cssChild : cssChildren) {
|
||||
applyUpdatesRecursive(
|
||||
cssChild, absoluteX + cssNode.getLayoutX(), absoluteY + cssNode.getLayoutY());
|
||||
cssChild,
|
||||
absoluteX + cssNode.getLayoutX(),
|
||||
absoluteY + cssNode.getLayoutY(),
|
||||
onLayoutNodes);
|
||||
}
|
||||
}
|
||||
|
||||
int tag = cssNode.getReactTag();
|
||||
if (!mShadowNodeRegistry.isRootNode(tag)) {
|
||||
boolean frameDidChange =
|
||||
cssNode.dispatchUpdates(
|
||||
absoluteX, absoluteY, mOperationsQueue, mNativeViewHierarchyOptimizer);
|
||||
cssNode.dispatchUpdates(absoluteX, absoluteY, mOperationsQueue, mNativeViewHierarchyOptimizer);
|
||||
|
||||
// Notify JS about layout event if requested
|
||||
// and if the position or dimensions actually changed
|
||||
// (consistent with iOS).
|
||||
if (frameDidChange && cssNode.shouldNotifyOnLayout()) {
|
||||
mEventDispatcher.dispatchEvent(
|
||||
OnLayoutEvent.obtain(
|
||||
-1, /* surfaceId not used in classic renderer */
|
||||
tag,
|
||||
cssNode.getScreenX(),
|
||||
cssNode.getScreenY(),
|
||||
cssNode.getScreenWidth(),
|
||||
cssNode.getScreenHeight()));
|
||||
}
|
||||
}
|
||||
cssNode.markUpdateSeen();
|
||||
mNativeViewHierarchyOptimizer.onViewUpdatesCompleted(cssNode);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user