Refactor the way UIManagerModule uses measure specs

Summary:
Instead of using measure specs to set certain yoga properties on the root node (like max width, auto width, specific width), use yoga's calculateLayout(width, height) instead. The measure specs will be stored in the shadow node. This allows us to remove duplicated code that processes the measure specs and allows us to remove other logic like the enableLayoutCalculation() method.

This diff also removes MeasureSpecProvider. MeasureSpecProvider was originally introduced to pass previously measured view measure specs to the initial creation of the root shadow node, but it turns out that this is unnecessary. We can update the root layout specs from the root view instead.

Reviewed By: mdvacca

Differential Revision: D9729744

fbshipit-source-id: 79b0b27ca879758f5dc3fc7cc8a0d38856a6cc79
This commit is contained in:
Luna Wei
2019-02-21 19:51:45 -08:00
committed by Facebook Github Bot
parent 9cb93abc47
commit e758435167
8 changed files with 52 additions and 116 deletions

View File

@@ -6,10 +6,6 @@
*/
package com.facebook.react.uimanager;
import static android.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.UNSPECIFIED;
import android.os.SystemClock;
import android.view.View;
import android.view.View.MeasureSpec;
@@ -25,11 +21,11 @@ import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.modules.i18nmanager.I18nUtil;
import com.facebook.react.uimanager.common.MeasureSpecProvider;
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.systrace.Systrace;
import com.facebook.systrace.SystraceMessage;
import com.facebook.yoga.YogaConstants;
import com.facebook.yoga.YogaDirection;
import java.util.Arrays;
import java.util.HashSet;
@@ -47,7 +43,6 @@ public class UIImplementation {
protected final EventDispatcher mEventDispatcher;
protected final ReactApplicationContext mReactContext;
protected final ShadowNodeRegistry mShadowNodeRegistry = new ShadowNodeRegistry();
private final Set<Integer> mMeasuredRootNodes = new HashSet<>();
private final ViewManagerRegistry mViewManagers;
private final UIViewOperationQueue mOperationsQueue;
private final NativeViewHierarchyOptimizer mNativeViewHierarchyOptimizer;
@@ -162,49 +157,19 @@ public class UIImplementation {
*/
public void updateRootView(
ReactShadowNode rootCSSNode, int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
switch (widthMode) {
case EXACTLY:
rootCSSNode.setStyleWidth(widthSize);
break;
case AT_MOST:
rootCSSNode.setStyleMaxWidth(widthSize);
break;
case UNSPECIFIED:
rootCSSNode.setStyleWidthAuto();
break;
}
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
switch (heightMode) {
case EXACTLY:
rootCSSNode.setStyleHeight(heightSize);
break;
case AT_MOST:
rootCSSNode.setStyleMaxHeight(heightSize);
break;
case UNSPECIFIED:
rootCSSNode.setStyleHeightAuto();
break;
}
rootCSSNode.setMeasureSpecs(widthMeasureSpec, heightMeasureSpec);
}
/**
* Registers a root node with a given tag, size and ThemedReactContext and adds it to a node
* registry.
*/
public <T extends View & MeasureSpecProvider> void registerRootView(
public <T extends View> void registerRootView(
T rootView, int tag, ThemedReactContext context) {
final ReactShadowNode rootCSSNode = createRootShadowNode();
rootCSSNode.setReactTag(tag);
rootCSSNode.setThemedContext(context);
int widthMeasureSpec = rootView.getWidthMeasureSpec();
int heightMeasureSpec = rootView.getHeightMeasureSpec();
updateRootView(rootCSSNode, widthMeasureSpec, heightMeasureSpec);
context.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
@@ -685,7 +650,7 @@ public class UIImplementation {
int tag = mShadowNodeRegistry.getRootTag(i);
ReactShadowNode cssRoot = mShadowNodeRegistry.getNode(tag);
if (mMeasuredRootNodes.contains(tag)) {
if (cssRoot.getWidthMeasureSpec() != null && cssRoot.getHeightMeasureSpec() != null) {
SystraceMessage.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"UIImplementation.notifyOnBeforeLayoutRecursive")
@@ -846,7 +811,6 @@ public class UIImplementation {
private void removeShadowNodeRecursive(ReactShadowNode nodeToRemove) {
NativeViewHierarchyOptimizer.handleRemoveNode(nodeToRemove);
mShadowNodeRegistry.removeNode(nodeToRemove.getReactTag());
mMeasuredRootNodes.remove(nodeToRemove.getReactTag());
for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) {
removeShadowNodeRecursive(nodeToRemove.getChildAt(i));
}
@@ -955,7 +919,15 @@ public class UIImplementation {
.flush();
long startTime = SystemClock.uptimeMillis();
try {
cssRoot.calculateLayout();
int widthSpec = cssRoot.getWidthMeasureSpec();
int heightSpec = cssRoot.getHeightMeasureSpec();
cssRoot.calculateLayout(
MeasureSpec.getMode(widthSpec) == MeasureSpec.UNSPECIFIED
? YogaConstants.UNDEFINED
: MeasureSpec.getSize(widthSpec),
MeasureSpec.getMode(heightSpec) == MeasureSpec.UNSPECIFIED
? YogaConstants.UNDEFINED
: MeasureSpec.getSize(heightSpec));
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
mLastCalculateLayoutTime = SystemClock.uptimeMillis() - startTime;
@@ -1029,15 +1001,6 @@ public class UIImplementation {
return rootTag;
}
/**
* Enables Layout calculation for a Root node that has been measured.
*
* @param rootViewTag {@link int} Tag of the root node
*/
public void enableLayoutCalculationForRootNode(int rootViewTag) {
this.mMeasuredRootNodes.add(rootViewTag);
}
public void setLayoutUpdateListener(LayoutUpdateListener listener) {
mLayoutUpdateListener = listener;
}