Files
react-native/ReactAndroid/src/main/java/com/facebook/react/flat/FlatShadowNode.java
Ahmed El-Helw 99d95d8168 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
2016-12-19 13:40:21 -08:00

292 lines
8.6 KiB
Java

/**
* 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 com.facebook.infer.annotation.Assertions;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.ViewProps;
/**
* FlatShadowNode is a base class for all shadow node used in FlatUIImplementation. It extends
* {@link LayoutShadowNode} by adding an ability to prepare DrawCommands off the UI thread.
*/
/* package */ class FlatShadowNode extends LayoutShadowNode {
/* package */ static final FlatShadowNode[] EMPTY_ARRAY = new FlatShadowNode[0];
private static final String PROP_DECOMPOSED_MATRIX = "decomposedMatrix";
private static final String PROP_OPACITY = "opacity";
private static final String PROP_RENDER_TO_HARDWARE_TEXTURE = "renderToHardwareTextureAndroid";
private static final String PROP_ACCESSIBILITY_LABEL = "accessibilityLabel";
private static final String PROP_ACCESSIBILITY_COMPONENT_TYPE = "accessibilityComponentType";
private static final String PROP_ACCESSIBILITY_LIVE_REGION = "accessibilityLiveRegion";
private static final String PROP_IMPORTANT_FOR_ACCESSIBILITY = "importantForAccessibility";
private static final String PROP_TEST_ID = "testID";
private DrawCommand[] mDrawCommands = DrawCommand.EMPTY_ARRAY;
private AttachDetachListener[] mAttachDetachListeners = AttachDetachListener.EMPTY_ARRAY;
private NodeRegion[] mNodeRegions = NodeRegion.EMPTY_ARRAY;
private FlatShadowNode[] mNativeChildren = FlatShadowNode.EMPTY_ARRAY;
private NodeRegion mNodeRegion = NodeRegion.EMPTY;
private int mNativeParentTag;
private int mViewLeft;
private int mViewTop;
private int mViewRight;
private int mViewBottom;
private boolean mBackingViewIsCreated;
private @Nullable DrawView mDrawView;
private @Nullable DrawBackgroundColor mDrawBackground;
private int mMoveToIndexInParent;
private boolean mClipToBounds = false;
/* package */ void handleUpdateProperties(ReactStylesDiffMap styles) {
if (!mountsToView()) {
// Make sure we mount this FlatShadowNode to a View if any of these properties are present.
if (styles.hasKey(PROP_DECOMPOSED_MATRIX) ||
styles.hasKey(PROP_OPACITY) ||
styles.hasKey(PROP_RENDER_TO_HARDWARE_TEXTURE) ||
styles.hasKey(PROP_TEST_ID) ||
styles.hasKey(PROP_ACCESSIBILITY_LABEL) ||
styles.hasKey(PROP_ACCESSIBILITY_COMPONENT_TYPE) ||
styles.hasKey(PROP_ACCESSIBILITY_LIVE_REGION) ||
styles.hasKey(PROP_IMPORTANT_FOR_ACCESSIBILITY)) {
forceMountToView();
}
}
}
/**
* Collects DrawCommands produced by this FlatShadowNode.
*/
protected void collectState(
StateBuilder stateBuilder,
float left,
float top,
float right,
float bottom,
float clipLeft,
float clipTop,
float clipRight,
float clipBottom) {
if (mDrawBackground != null) {
mDrawBackground = (DrawBackgroundColor) mDrawBackground.updateBoundsAndFreeze(
left,
top,
right,
bottom,
clipLeft,
clipTop,
clipRight,
clipBottom);
stateBuilder.addDrawCommand(mDrawBackground);
}
}
@ReactProp(name = ViewProps.BACKGROUND_COLOR)
public void setBackgroundColor(int backgroundColor) {
mDrawBackground = (backgroundColor == 0) ? null : new DrawBackgroundColor(backgroundColor);
invalidate();
}
@ReactProp(name = "overflow")
public void setOverflow(String overflow) {
mClipToBounds = "hidden".equals(overflow);
invalidate();
}
public final boolean clipToBounds() {
return mClipToBounds;
}
@Override
public final int getScreenX() {
return mViewLeft;
}
@Override
public final int getScreenY() {
return mViewTop;
}
@Override
public final int getScreenWidth() {
return mViewRight - mViewLeft;
}
@Override
public final int getScreenHeight() {
return mViewBottom - mViewTop;
}
/**
* Marks root node as updated to trigger a StateBuilder pass to collect DrawCommands for the node
* tree. Use it when FlatShadowNode is updated but doesn't require a layout pass (e.g. background
* color is changed).
*/
protected final void invalidate() {
((FlatRootShadowNode) getRootNode()).markUpdated(true);
}
/**
* Returns an array of DrawCommands to perform during the View's draw pass.
*/
/* package */ DrawCommand[] getDrawCommands() {
return mDrawCommands;
}
/**
* Sets an array of DrawCommands to perform during the View's draw pass. StateBuilder uses old
* draw commands to compare to new draw commands and see if the View neds to be redrawn.
*/
/* package */ void setDrawCommands(DrawCommand[] drawCommands) {
mDrawCommands = drawCommands;
}
/**
* Sets an array of AttachDetachListeners to call onAttach/onDetach when they are attached to or
* detached from a View that this shadow node maps to.
*/
/* package */ void setAttachDetachListeners(AttachDetachListener[] listeners) {
mAttachDetachListeners = listeners;
}
/**
* Returns an array of AttachDetachListeners associated with this shadow node.
*/
/* package */ AttachDetachListener[] getAttachDetachListeners() {
return mAttachDetachListeners;
}
/* package */ final FlatShadowNode[] getNativeChildren() {
return mNativeChildren;
}
/* package */ final void setNativeChildren(FlatShadowNode[] nativeChildren) {
mNativeChildren = nativeChildren;
}
/* package */ final int getNativeParentTag() {
return mNativeParentTag;
}
/* package */ final void setNativeParentTag(int nativeParentTag) {
mNativeParentTag = nativeParentTag;
}
/* package */ final NodeRegion[] getNodeRegions() {
return mNodeRegions;
}
/* package */ final void setNodeRegions(NodeRegion[] nodeRegion) {
mNodeRegions = nodeRegion;
}
/* package */ final void setMoveToIndexInParent(int moveToIndexInParent) {
mMoveToIndexInParent = moveToIndexInParent;
}
/* package */ final int getMoveToIndexInParent() {
return mMoveToIndexInParent;
}
/* package */ void updateNodeRegion(float left, float top, float right, float bottom) {
if (mNodeRegion.mLeft != left || mNodeRegion.mTop != top ||
mNodeRegion.mRight != right || mNodeRegion.mBottom != bottom) {
setNodeRegion(new NodeRegion(left, top, right, bottom, getReactTag()));
}
}
protected final void setNodeRegion(NodeRegion nodeRegion) {
mNodeRegion = nodeRegion;
}
/* package */ final NodeRegion getNodeRegion() {
return mNodeRegion;
}
/**
* Sets boundaries of the View that this node maps to relative to the parent left/top coordinate.
*/
/* package */ void setViewBounds(int left, int top, int right, int bottom) {
mViewLeft = left;
mViewTop = top;
mViewRight = right;
mViewBottom = bottom;
}
/**
* Left position of the View this node maps to relative to the parent View.
*/
/* package */ int getViewLeft() {
return mViewLeft;
}
/**
* Top position of the View this node maps to relative to the parent View.
*/
/* package */ int getViewTop() {
return mViewTop;
}
/**
* Right position of the View this node maps to relative to the parent View.
*/
/* package */ int getViewRight() {
return mViewRight;
}
/**
* Bottom position of the View this node maps to relative to the parent View.
*/
/* package */ int getViewBottom() {
return mViewBottom;
}
/* package */ final void forceMountToView() {
if (isVirtual()) {
return;
}
if (mDrawView == null) {
mDrawView = DrawView.INSTANCE;
if (getParent() != null) {
invalidate();
}
// reset NodeRegion to allow it getting garbage-collected
mNodeRegion = NodeRegion.EMPTY;
}
}
/* package */ final DrawView collectDrawView(float left, float top, float right, float bottom) {
if (!Assertions.assumeNotNull(mDrawView).clipBoundsMatch(left, top, right, bottom)) {
mDrawView = new DrawView(left, top, right, bottom);
}
return mDrawView;
}
/* package */ final boolean mountsToView() {
return mDrawView != null;
}
/* package */ final boolean isBackingViewCreated() {
return mBackingViewIsCreated;
}
/* package */ final void signalBackingViewIsCreated() {
mBackingViewIsCreated = true;
}
}