From 99d95d816832c9ba4b7aa2ad408adaca289d1bf3 Mon Sep 17 00:00:00 2001 From: Ahmed El-Helw Date: Fri, 12 Feb 2016 20:16:23 -0800 Subject: [PATCH] Fix TextInput in React Nodes Summary: @public Relax the constraint on ReactTextInputManager. The TextInput Advanced screen looked different with and without nodes, namely child Text items were not being rendered on the Nodes version. This patch fixes that. Differential Revision: D2930800 --- .../facebook/react/flat/FlatShadowNode.java | 2 +- .../react/flat/FlatTextShadowNode.java | 5 ++ .../react/flat/FlatUIImplementation.java | 3 +- .../com/facebook/react/flat/RCTTextInput.java | 90 +++++++++++++++++++ .../react/flat/RCTTextInputManager.java | 25 ++++++ .../com/facebook/react/flat/StateBuilder.java | 17 +++- 6 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInputManager.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatShadowNode.java index 67ea71237..8beffc672 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatShadowNode.java @@ -67,7 +67,7 @@ import com.facebook.react.uimanager.ViewProps; } /** - * Collects DrawCommands produced by this FlatShadoNode. + * Collects DrawCommands produced by this FlatShadowNode. */ protected void collectState( StateBuilder stateBuilder, diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatTextShadowNode.java index 6bea964ae..4432a78d5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatTextShadowNode.java @@ -30,6 +30,11 @@ import com.facebook.react.uimanager.ReactShadowNode; if (parent instanceof FlatTextShadowNode) { ((FlatTextShadowNode) parent).notifyChanged(shouldRemeasure); } + + if (this instanceof RCTTextInput) { + // needed to trigger onCollectExtraUpdates + markUpdated(); + } } @Override 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 78dcb71cc..62182d283 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatUIImplementation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatUIImplementation.java @@ -58,13 +58,14 @@ public class FlatUIImplementation extends UIImplementation { TypefaceCache.setAssetManager(reactContext.getAssets()); - viewManagers = new ArrayList(viewManagers); + viewManagers = new ArrayList<>(viewManagers); viewManagers.add(new RCTViewManager()); viewManagers.add(new RCTTextManager()); viewManagers.add(new RCTRawTextManager()); viewManagers.add(new RCTVirtualTextManager()); viewManagers.add(new RCTTextInlineImageManager()); viewManagers.add(new RCTImageViewManager()); + viewManagers.add(new RCTTextInputManager()); ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers); FlatNativeViewHierarchyManager nativeViewHierarchyManager = new FlatNativeViewHierarchyManager( diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java new file mode 100644 index 000000000..c4f942f5d --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java @@ -0,0 +1,90 @@ +/** + * 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 javax.annotation.Nullable; + +import android.text.SpannableStringBuilder; + +import com.facebook.csslayout.Spacing; +import com.facebook.react.uimanager.UIViewOperationQueue; +import com.facebook.react.uimanager.annotations.ReactProp; +import com.facebook.react.views.text.ReactTextUpdate; + +import static com.facebook.react.views.text.ReactTextShadowNode.UNSET; + +public class RCTTextInput extends RCTVirtualText { + private int mJsEventCount = UNSET; + private @Nullable float[] mComputedPadding; + + public RCTTextInput() { + forceMountToView(); + } + + @Override + public boolean isVirtual() { + return false; + } + + @Override + public boolean isVirtualAnchor() { + return true; + } + + @Override + public void setBackgroundColor(int backgroundColor) { + // suppress, this is handled by a ViewManager + } + + @Override + public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) { + super.onCollectExtraUpdates(uiViewOperationQueue); + + if (mComputedPadding != null) { + uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), mComputedPadding); + mComputedPadding = null; + } + + ReactTextUpdate reactTextUpdate = + new ReactTextUpdate(getText(), mJsEventCount, false); + uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate); + } + + @ReactProp(name = "mostRecentEventCount") + public void setMostRecentEventCount(int mostRecentEventCount) { + mJsEventCount = mostRecentEventCount; + } + + @Override + public void setPadding(int spacingType, float padding) { + super.setPadding(spacingType, padding); + mComputedPadding = spacingToFloatArray(getPadding()); + markUpdated(); + } + + private static float[] spacingToFloatArray(Spacing spacing) { + return new float[] { + spacing.get(Spacing.LEFT), + spacing.get(Spacing.TOP), + spacing.get(Spacing.RIGHT), + spacing.get(Spacing.BOTTOM), + }; + } + + /** + * Returns a new CharSequence that includes all the text and styling information to create Layout. + */ + SpannableStringBuilder getText() { + SpannableStringBuilder sb = new SpannableStringBuilder(); + collectText(sb); + applySpans(sb); + return sb; + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInputManager.java new file mode 100644 index 000000000..66eea3fd2 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInputManager.java @@ -0,0 +1,25 @@ +/** + * 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.react.views.textinput.ReactTextInputManager; + +/* package */ class RCTTextInputManager extends ReactTextInputManager { + + @Override + public RCTTextInput createShadowNodeInstance() { + return new RCTTextInput(); + } + + @Override + public Class getShadowNodeClass() { + return RCTTextInput.class; + } +} 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 f0622089d..ff0480127 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/StateBuilder.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/StateBuilder.java @@ -9,14 +9,14 @@ package com.facebook.react.flat; -import java.util.ArrayList; - import javax.annotation.Nullable; +import java.util.ArrayList; + import com.facebook.csslayout.CSSNode; import com.facebook.csslayout.Spacing; -import com.facebook.react.uimanager.ReactStylesDiffMap; import com.facebook.react.uimanager.OnLayoutEvent; +import com.facebook.react.uimanager.ReactStylesDiffMap; import com.facebook.react.uimanager.events.EventDispatcher; /** @@ -240,7 +240,11 @@ import com.facebook.react.uimanager.events.EventDispatcher; isAndroidView, needsCustomLayoutForChildren); - if (node.isVirtualAnchor()) { + // this is a temporary measure to skip adding node regions for RCTTextInput. This will be fixed + // in a patch soon which will convert AndroidView into an interface, thus allowing RCTTextInput + // to be treated as an AndroidView + boolean skipAddingNodeRegion = node instanceof RCTTextInput; + if (!isAndroidView && node.isVirtualAnchor() && !skipAddingNodeRegion) { // If RCTText is mounted to View, virtual children will not receive any touch events // because they don't get added to nodeRegions, so nodeRegions will be empty and // FlatViewGroup.reactTagForTouch() will always return RCTText's id. To fix the issue, @@ -276,6 +280,11 @@ import com.facebook.react.uimanager.events.EventDispatcher; nodeRegions); } + if (node.hasUpdates()) { + node.onCollectExtraUpdates(mOperationsQueue); + node.markUpdateSeen(); + } + final FlatShadowNode[] nativeChildren = mNativeChildren.finish(); if (nativeChildren != null) { updateNativeChildren(node, tag, node.getNativeChildren(), nativeChildren);