diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/AndroidView.java b/ReactAndroid/src/main/java/com/facebook/react/flat/AndroidView.java new file mode 100644 index 000000000..14bc87437 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/AndroidView.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package com.facebook.react.flat; + +import com.facebook.csslayout.CSSNode; +import com.facebook.react.uimanager.CatalystStylesDiffMap; +import com.facebook.react.uimanager.ReactShadowNode; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.ViewGroupManager; +import com.facebook.react.uimanager.ViewManager; + +/* package */ final class AndroidView extends FlatShadowNode { + + final ViewManager mViewManager; + private final ReactShadowNode mReactShadowNode; + private final boolean mNeedsCustomLayoutForChildren; + + /* package */ AndroidView(ViewManager viewManager) { + mViewManager = viewManager; + ReactShadowNode reactShadowNode = viewManager.createShadowNodeInstance(); + if (reactShadowNode instanceof CSSNode.MeasureFunction) { + mReactShadowNode = reactShadowNode; + setMeasureFunction((CSSNode.MeasureFunction) reactShadowNode); + } else { + mReactShadowNode = null; + } + + if (viewManager instanceof ViewGroupManager) { + ViewGroupManager viewGroupManager = (ViewGroupManager) viewManager; + mNeedsCustomLayoutForChildren = viewGroupManager.needsCustomLayoutForChildren(); + } else { + mNeedsCustomLayoutForChildren = false; + } + + forceMountToView(); + } + + /* package */ boolean needsCustomLayoutForChildren() { + return mNeedsCustomLayoutForChildren; + } + + @Override + public void setBackgroundColor(int backgroundColor) { + // suppress, this is handled by a ViewManager + } + + @Override + public void setThemedContext(ThemedReactContext themedContext) { + super.setThemedContext(themedContext); + + if (mReactShadowNode != null) { + mReactShadowNode.setThemedContext(themedContext); + } + } + + @Override + /* package*/ void handleUpdateProperties(CatalystStylesDiffMap styles) { + if (mReactShadowNode != null) { + mReactShadowNode.updateProperties(styles); + } + } + + @Override + public void addChildAt(CSSNode child, int i) { + super.addChildAt(child, i); + ((FlatShadowNode) child).forceMountToView(); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatNativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatNativeViewHierarchyManager.java index d6c80e423..37b454012 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatNativeViewHierarchyManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatNativeViewHierarchyManager.java @@ -13,10 +13,12 @@ import javax.annotation.Nullable; import android.view.View; import android.view.View.MeasureSpec; +import android.view.ViewGroup; import com.facebook.react.uimanager.NativeViewHierarchyManager; import com.facebook.react.uimanager.SizeMonitoringFrameLayout; import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.ViewGroupManager; import com.facebook.react.uimanager.ViewManagerRegistry; /** @@ -71,8 +73,18 @@ import com.facebook.react.uimanager.ViewManagerRegistry; } /* package */ void updateViewGroup(int reactTag, int[] viewsToAdd, int[] viewsToDetach) { - FlatViewGroup view = (FlatViewGroup) resolveView(reactTag); - view.mountViews(this, viewsToAdd, viewsToDetach); + View view = resolveView(reactTag); + if (view instanceof FlatViewGroup) { + ((FlatViewGroup) view).mountViews(this, viewsToAdd, viewsToDetach); + return; + } + + ViewGroup viewGroup = (ViewGroup) view; + ViewGroupManager viewManager = (ViewGroupManager) resolveViewManager(reactTag); + for (int i = 0; i < viewsToAdd.length; ++i) { + int tag = Math.abs(viewsToAdd[i]); + viewManager.addView(viewGroup, resolveView(tag), i); + } } /** @@ -103,8 +115,17 @@ import com.facebook.react.uimanager.ViewManagerRegistry; /* package */ void detachAllChildrenFromViews(int[] viewsToDetachAllChildrenFrom) { for (int viewTag : viewsToDetachAllChildrenFrom) { - FlatViewGroup viewGroup = (FlatViewGroup) resolveView(viewTag); - viewGroup.detachAllViewsFromParent(); + View view = resolveView(viewTag); + if (view instanceof FlatViewGroup) { + ((FlatViewGroup) view).detachAllViewsFromParent(); + continue; + } + + ViewGroup viewGroup = (ViewGroup) view; + ViewGroupManager viewManager = (ViewGroupManager) resolveViewManager(viewTag); + for (int i = viewManager.getChildCount(viewGroup) - 1; i >= 0; --i) { + viewManager.removeViewAt(viewGroup, i); + } } } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatUIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatUIImplementation.java index dfd5fce61..adf9b5e30 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatUIImplementation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatUIImplementation.java @@ -76,6 +76,16 @@ public class FlatUIImplementation extends UIImplementation { } @Override + protected ReactShadowNode createShadowNode(String className) { + ReactShadowNode cssNode = super.createShadowNode(className); + if (cssNode instanceof FlatShadowNode) { + return cssNode; + } + + ViewManager viewManager = resolveViewManager(className); + return new AndroidView(viewManager); + } + protected void handleCreateView( ReactShadowNode cssNode, int rootViewTag, diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/StateBuilder.java b/ReactAndroid/src/main/java/com/facebook/react/flat/StateBuilder.java index bc1dd9e3c..97eebb79f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/StateBuilder.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/StateBuilder.java @@ -149,7 +149,14 @@ import com.facebook.react.uimanager.CatalystStylesDiffMap; mNodeRegions.start(node.getNodeRegions()); mNativeChildren.start(node.getNativeChildren()); - collectStateRecursively(node, 0, 0, width, height); + boolean isAndroidView = false; + boolean needsCustomLayoutForChildren = false; + if (node instanceof AndroidView) { + isAndroidView = true; + needsCustomLayoutForChildren = ((AndroidView) node).needsCustomLayoutForChildren(); + } + + collectStateRecursively(node, 0, 0, width, height, isAndroidView, needsCustomLayoutForChildren); boolean shouldUpdateMountState = false; final DrawCommand[] drawCommands = mDrawCommands.finish(); @@ -248,7 +255,9 @@ import com.facebook.react.uimanager.CatalystStylesDiffMap; float left, float top, float right, - float bottom) { + float bottom, + boolean isAndroidView, + boolean needsCustomLayoutForChildren) { if (node.hasNewLayout()) { node.markLayoutSeen(); } @@ -257,7 +266,7 @@ import com.facebook.react.uimanager.CatalystStylesDiffMap; for (int i = 0, childCount = node.getChildCount(); i != childCount; ++i) { FlatShadowNode child = (FlatShadowNode) node.getChildAt(i); - processNodeAndCollectState(child, left, top); + processNodeAndCollectState(child, left, top, isAndroidView, needsCustomLayoutForChildren); } } @@ -267,7 +276,9 @@ import com.facebook.react.uimanager.CatalystStylesDiffMap; private void processNodeAndCollectState( FlatShadowNode node, float parentLeft, - float parentTop) { + float parentTop, + boolean parentIsAndroidView, + boolean needsCustomLayout) { int tag = node.getReactTag(); float width = node.getLayoutWidth(); @@ -284,12 +295,17 @@ import com.facebook.react.uimanager.CatalystStylesDiffMap; ensureBackingViewIsCreated(node, tag, null); addNativeChild(node); - mDrawCommands.add(DrawView.INSTANCE); + if (!parentIsAndroidView) { + mDrawCommands.add(DrawView.INSTANCE); + } collectStateForMountableNode(node, tag, width, height); - mViewsToUpdateBounds.add(node); + + if (!needsCustomLayout) { + mViewsToUpdateBounds.add(node); + } } else { - collectStateRecursively(node, left, top, right, bottom); + collectStateRecursively(node, left, top, right, bottom, false, false); addNodeRegion(node.getNodeRegion()); } }