From c0c388c8aa84264f243e0160b1fd0a8ffeee6ed2 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Thu, 1 Mar 2018 10:24:16 -0800 Subject: [PATCH] Adding simple View rendering support using FabricUIManager. Reviewed By: achen1 Differential Revision: D7102725 fbshipit-source-id: d2878d036843ba01201c4df617680269b5f59039 --- .../react/fabric/FabricUIManagerModule.java | 94 +++++++++++++++++-- 1 file changed, 84 insertions(+), 10 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerModule.java index e291d2188..57a751600 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerModule.java @@ -3,15 +3,19 @@ package com.facebook.react.fabric; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.bridge.JavaOnlyArray; import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableNativeMap; import com.facebook.react.bridge.UIManager; import com.facebook.react.modules.i18nmanager.I18nUtil; +import com.facebook.react.uimanager.NativeViewHierarchyManager; import com.facebook.react.uimanager.ReactRootViewTagGenerator; import com.facebook.react.uimanager.ReactShadowNode; import com.facebook.react.uimanager.ReactShadowNodeImpl; import com.facebook.react.uimanager.ReactStylesDiffMap; import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.UIViewOperationQueue; import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManagerRegistry; import com.facebook.react.uimanager.common.MeasureSpecProvider; @@ -19,6 +23,7 @@ import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout; import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; + /** * This class is responsible to create, clone and update {@link ReactShadowNode} using the * Fabric API. @@ -26,14 +31,17 @@ import javax.annotation.Nullable; @SuppressWarnings("unused") // used from JNI public class FabricUIManagerModule implements UIManager { + private static final String TAG = FabricUIManagerModule.class.toString(); private final RootShadowNodeRegistry mRootShadowNodeRegistry = new RootShadowNodeRegistry(); private final ReactApplicationContext mReactApplicationContext; private final ViewManagerRegistry mViewManagerRegistry; + private final UIViewOperationQueue mUIViewOperationQueue; public FabricUIManagerModule(ReactApplicationContext reactContext, - ViewManagerRegistry viewManagerRegistry) { + ViewManagerRegistry viewManagerRegistry) { mReactApplicationContext = reactContext; mViewManagerRegistry = viewManagerRegistry; + mUIViewOperationQueue = new UIViewOperationQueue(reactContext, new NativeViewHierarchyManager(viewManagerRegistry), 0); } /** @@ -41,16 +49,21 @@ public class FabricUIManagerModule implements UIManager { */ @Nullable public ReactShadowNode createNode(int reactTag, - String viewName, - int rootTag, - ReadableNativeMap props) { + String viewName, + int rootTag, + ReadableNativeMap props) { ViewManager viewManager = mViewManagerRegistry.get(viewName); ReactShadowNode node = viewManager.createShadowNodeInstance(mReactApplicationContext); - node.setRootNode(getRootNode(rootTag)); + ReactShadowNode rootNode = getRootNode(rootTag); + node.setRootNode(rootNode); node.setReactTag(reactTag); + node.setThemedContext(rootNode.getThemedContext()); + ReactStylesDiffMap styles = updateProps(node, props); + mUIViewOperationQueue + .enqueueCreateView(rootNode.getThemedContext(), reactTag, viewName, styles); return node; } @@ -135,6 +148,7 @@ public class FabricUIManagerModule implements UIManager { @Nullable public void appendChild(ReactShadowNode parent, ReactShadowNode child) { parent.addChildAt(child, parent.getChildCount()); + setChildren(parent.getReactTag(), child.getReactTag()); } /** @@ -153,8 +167,60 @@ public class FabricUIManagerModule implements UIManager { } public void completeRoot(int rootTag, List childList) { - // TODO Diffing old Tree with new Tree - // Do we need to hold references to old and new tree? + if (!childList.isEmpty()) { + ReactShadowNode rootNode = getRootNode(rootTag); + for (int i = 0; i < childList.size(); i++) { + ReactShadowNode child = childList.get(i); + rootNode.addChildAt(child, i); + setChildren(rootTag, child.getReactTag()); + } + + calculateRootLayout(rootNode); + applyUpdatesRecursive(rootNode, 0, 0); + mUIViewOperationQueue.dispatchViewUpdates(1, System.currentTimeMillis(), System.currentTimeMillis()); + } + } + + private void setChildren(int parent, int child) { + JavaOnlyArray childrenTags = new JavaOnlyArray(); + childrenTags.pushInt(child); + mUIViewOperationQueue.enqueueSetChildren( + parent, + childrenTags + ); + } + + private void calculateRootLayout(ReactShadowNode cssRoot) { + cssRoot.calculateLayout(); + } + + private void applyUpdatesRecursive( + ReactShadowNode cssNode, + float absoluteX, + float absoluteY) { + + if (!cssNode.hasUpdates()) { + return; + } + + if (!cssNode.isVirtualAnchor()) { + for (int i = 0; i < cssNode.getChildCount(); i++) { + applyUpdatesRecursive( + cssNode.getChildAt(i), + absoluteX + cssNode.getLayoutX(), + absoluteY + cssNode.getLayoutY()); + } + } + + int tag = cssNode.getReactTag(); + if (mRootShadowNodeRegistry.getNode(tag) == null) { + boolean frameDidChange = cssNode.dispatchUpdates( + absoluteX, + absoluteY, + mUIViewOperationQueue, + null); + } + cssNode.markUpdateSeen(); } @Override @@ -162,10 +228,18 @@ public class FabricUIManagerModule implements UIManager { final T rootView) { int rootTag = ReactRootViewTagGenerator.getNextRootViewTag(); ThemedReactContext themedRootContext = new ThemedReactContext( - mReactApplicationContext, - rootView.getContext()); + mReactApplicationContext, + rootView.getContext()); - mRootShadowNodeRegistry.addNode(createRootShadowNode(rootTag, themedRootContext)); + ReactShadowNode rootShadowNode = createRootShadowNode(rootTag, themedRootContext); + + int widthMeasureSpec = rootView.getWidthMeasureSpec(); + int heightMeasureSpec = rootView.getHeightMeasureSpec(); + rootShadowNode.setStyleWidthAuto(); + rootShadowNode.setStyleHeightAuto(); + + mRootShadowNodeRegistry.addNode(rootShadowNode); + mUIViewOperationQueue.addRootView(rootTag, rootView, themedRootContext); return rootTag; }