Skip to content

Android Paper top-down onLayout events #39644

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,32 @@ public void onAfterUpdateTransaction() {
@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,
Expand Down Expand Up @@ -386,10 +409,6 @@ public boolean dispatchUpdates(
getScreenHeight());
}
}

return layoutHasChanged;
} else {
return false;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
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;

/**
Expand Down Expand Up @@ -665,7 +667,20 @@ protected void updateViewHierarchy() {
.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);
}
Expand Down Expand Up @@ -951,39 +966,34 @@ protected void calculateRootLayout(ReactShadowNode cssRoot) {
}
}

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);

// 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.dispatchUpdates(absoluteX, absoluteY, mOperationsQueue, mNativeViewHierarchyOptimizer);

cssNode.markUpdateSeen();
mNativeViewHierarchyOptimizer.onViewUpdatesCompleted(cssNode);
}
Expand Down