Backed out changeset 7c338fe3b747
Reviewed By: AaaChiuuu Differential Revision: D5926999 fbshipit-source-id: 58595f74f1fab764b63b5d7d6c2f20d8edb2efda
This commit is contained in:
parent
672db77eae
commit
9b3cc30357
|
@ -15,9 +15,10 @@ import android.graphics.Point;
|
|||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManager;
|
||||
import com.facebook.react.uimanager.ReactShadowNodeImpl;
|
||||
import com.facebook.yoga.YogaUnit;
|
||||
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
import com.facebook.yoga.YogaValue;
|
||||
import com.facebook.yoga.YogaUnit;
|
||||
|
||||
/**
|
||||
* FlatReactModalShadowNode
|
||||
|
@ -42,11 +43,11 @@ class FlatReactModalShadowNode extends FlatShadowNode implements AndroidView {
|
|||
|
||||
/**
|
||||
* We need to set the styleWidth and styleHeight of the one child (represented by the <View/>
|
||||
* within the <RCTModalHostView/> in Modal.js. This needs to fill the entire window.
|
||||
* within the <RCTModalHostView/> in Modal.js. This needs to fill the entire window.
|
||||
*/
|
||||
@Override
|
||||
@TargetApi(16)
|
||||
public void addChildAt(ReactShadowNodeImpl child, int i) {
|
||||
public void addChildAt(ReactShadowNode child, int i) {
|
||||
super.addChildAt(child, i);
|
||||
|
||||
Context context = getThemedContext();
|
||||
|
|
|
@ -9,17 +9,18 @@
|
|||
|
||||
package com.facebook.react.flat;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.graphics.Rect;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.uimanager.OnLayoutEvent;
|
||||
import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
import com.facebook.react.uimanager.ReactShadowNodeImpl;
|
||||
import com.facebook.react.uimanager.ReactStylesDiffMap;
|
||||
import com.facebook.react.uimanager.ViewProps;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import javax.annotation.Nullable;
|
||||
import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
|
||||
|
||||
/**
|
||||
* FlatShadowNode is a base class for all shadow node used in FlatUIImplementation. It extends
|
||||
|
@ -212,7 +213,7 @@ import javax.annotation.Nullable;
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addChildAt(ReactShadowNodeImpl child, int i) {
|
||||
public void addChildAt(ReactShadowNode child, int i) {
|
||||
super.addChildAt(child, i);
|
||||
if (mForceMountChildrenToView && child instanceof FlatShadowNode) {
|
||||
((FlatShadowNode) child).forceMountToView();
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
|
||||
package com.facebook.react.flat;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
import com.facebook.react.uimanager.ReactShadowNodeImpl;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Helper class that sorts moveFrom/moveTo arrays in lockstep.
|
||||
|
@ -23,7 +23,7 @@ import javax.annotation.Nullable;
|
|||
private @Nullable ReadableArray mMoveTo;
|
||||
private int mSize;
|
||||
private int[] mMapping = new int[8];
|
||||
private ReactShadowNode[] mChildren = new ReactShadowNodeImpl[4];
|
||||
private ReactShadowNode[] mChildren = new ReactShadowNode[4];
|
||||
|
||||
/**
|
||||
* Retuns size of underlying moveTo/moveFrom arrays
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
package com.facebook.react.flat;
|
||||
|
||||
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;
|
||||
|
@ -19,6 +18,7 @@ import com.facebook.react.uimanager.ViewManager;
|
|||
import com.facebook.yoga.YogaMeasureFunction;
|
||||
import com.facebook.yoga.YogaUnit;
|
||||
import com.facebook.yoga.YogaValue;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/* package */ final class NativeViewWrapper extends FlatShadowNode implements AndroidView {
|
||||
|
@ -95,7 +95,7 @@ import javax.annotation.Nullable;
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addChildAt(ReactShadowNodeImpl child, int i) {
|
||||
public void addChildAt(ReactShadowNode child, int i) {
|
||||
super.addChildAt(child, i);
|
||||
if (mForceMountGrandChildrenToView && child instanceof FlatShadowNode) {
|
||||
((FlatShadowNode) child).forceMountChildrenToView();
|
||||
|
|
|
@ -9,16 +9,18 @@
|
|||
|
||||
package com.facebook.react.flat;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.ReactShadowNodeImpl;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
import com.facebook.react.uimanager.ViewProps;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* RCTVirtualText is a {@link FlatTextShadowNode} that can contain font styling information.
|
||||
|
@ -38,7 +40,7 @@ import javax.annotation.Nullable;
|
|||
private ShadowStyleSpan mShadowStyleSpan = ShadowStyleSpan.INSTANCE;
|
||||
|
||||
@Override
|
||||
public void addChildAt(ReactShadowNodeImpl child, int i) {
|
||||
public void addChildAt(ReactShadowNode child, int i) {
|
||||
super.addChildAt(child, i);
|
||||
notifyChanged(true);
|
||||
}
|
||||
|
|
|
@ -2,36 +2,6 @@
|
|||
|
||||
package com.facebook.react.processing;
|
||||
|
||||
import static javax.lang.model.element.Modifier.ABSTRACT;
|
||||
import static javax.lang.model.element.Modifier.PRIVATE;
|
||||
import static javax.lang.model.element.Modifier.PUBLIC;
|
||||
import static javax.tools.Diagnostic.Kind.ERROR;
|
||||
import static javax.tools.Diagnostic.Kind.WARNING;
|
||||
|
||||
import com.facebook.infer.annotation.SuppressFieldNotInitialized;
|
||||
import com.facebook.react.bridge.Dynamic;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.CodeBlock;
|
||||
import com.squareup.javapoet.JavaFile;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeVariableName;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.Filer;
|
||||
|
@ -50,6 +20,37 @@ import javax.lang.model.type.TypeMirror;
|
|||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.facebook.infer.annotation.SuppressFieldNotInitialized;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.Dynamic;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.CodeBlock;
|
||||
import com.squareup.javapoet.JavaFile;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeVariableName;
|
||||
|
||||
import static javax.lang.model.element.Modifier.*;
|
||||
import static javax.tools.Diagnostic.Kind.ERROR;
|
||||
import static javax.tools.Diagnostic.Kind.WARNING;
|
||||
|
||||
/**
|
||||
* This annotation processor crawls subclasses of ReactShadowNode and ViewManager and finds their
|
||||
* exported properties with the @ReactProp or @ReactGroupProp annotation. It generates a class
|
||||
|
@ -229,12 +230,13 @@ public class ReactPropertyProcessor extends AbstractProcessor {
|
|||
TypeName typeName = TypeName.get(mirror);
|
||||
if (typeName instanceof ParameterizedTypeName) {
|
||||
ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) typeName;
|
||||
if (parameterizedTypeName.rawType.equals(VIEW_MANAGER_TYPE)
|
||||
|| parameterizedTypeName.rawType.equals(SHADOW_NODE_TYPE)) {
|
||||
if (parameterizedTypeName.rawType.equals(VIEW_MANAGER_TYPE)) {
|
||||
return parameterizedTypeName.typeArguments.get(0);
|
||||
}
|
||||
} else if (typeName.equals(SHADOW_NODE_TYPE)) {
|
||||
return SHADOW_NODE_TYPE;
|
||||
} else if (typeName.equals(TypeName.OBJECT)) {
|
||||
throw new IllegalArgumentException("Could not find target type " + typeName);
|
||||
throw new IllegalArgumentException("Could not find target type");
|
||||
}
|
||||
|
||||
List<? extends TypeMirror> types = mTypes.directSupertypes(mirror);
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
import com.facebook.react.bridge.Dynamic;
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReadableType;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
|
||||
import com.facebook.yoga.YogaAlign;
|
||||
import com.facebook.yoga.YogaConstants;
|
||||
import com.facebook.yoga.YogaDisplay;
|
||||
|
@ -16,18 +18,19 @@ import com.facebook.yoga.YogaOverflow;
|
|||
import com.facebook.yoga.YogaPositionType;
|
||||
import com.facebook.yoga.YogaUnit;
|
||||
import com.facebook.yoga.YogaWrap;
|
||||
import javax.annotation.Nullable;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
|
||||
/**
|
||||
* Supply setters for base view layout properties such as width, height, flex properties, borders,
|
||||
* etc.
|
||||
* Supply setters for base view layout properties such as width, height, flex properties,
|
||||
* borders, etc.
|
||||
*
|
||||
* <p>Checking for isVirtual everywhere is a hack to get around the fact that some virtual nodes
|
||||
* still have layout properties set on them in JS: for example, a component that returns a <Text>
|
||||
* may or may not be embedded in a parent text. There are better solutions that should probably be
|
||||
* Checking for isVirtual everywhere is a hack to get around the fact that some virtual nodes still
|
||||
* have layout properties set on them in JS: for example, a component that returns a <Text> may
|
||||
* or may not be embedded in a parent text. There are better solutions that should probably be
|
||||
* explored, namely using the VirtualText class in JS and setting the correct set of validAttributes
|
||||
*/
|
||||
public class LayoutShadowNode extends ReactShadowNodeImpl {
|
||||
public class LayoutShadowNode extends ReactShadowNode {
|
||||
|
||||
/**
|
||||
* A Mutable version of com.facebook.yoga.YogaValue
|
||||
|
|
|
@ -9,180 +9,476 @@
|
|||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.facebook.yoga.YogaAlign;
|
||||
import com.facebook.yoga.YogaBaselineFunction;
|
||||
import com.facebook.yoga.YogaDirection;
|
||||
import com.facebook.yoga.YogaConfig;
|
||||
import com.facebook.yoga.YogaDisplay;
|
||||
import com.facebook.yoga.YogaEdge;
|
||||
import com.facebook.yoga.YogaConstants;
|
||||
import com.facebook.yoga.YogaDirection;
|
||||
import com.facebook.yoga.YogaFlexDirection;
|
||||
import com.facebook.yoga.YogaJustify;
|
||||
import com.facebook.yoga.YogaBaselineFunction;
|
||||
import com.facebook.yoga.YogaMeasureFunction;
|
||||
import com.facebook.yoga.YogaNode;
|
||||
import com.facebook.yoga.YogaOverflow;
|
||||
import com.facebook.yoga.YogaPositionType;
|
||||
import com.facebook.yoga.YogaValue;
|
||||
import com.facebook.yoga.YogaWrap;
|
||||
import javax.annotation.Nullable;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
|
||||
|
||||
/**
|
||||
* Base node class for representing virtual tree of React nodes. Shadow nodes are used primarily for
|
||||
* layouting therefore it extends {@link YogaNode} to allow that. They also help with handling
|
||||
* Base node class for representing virtual tree of React nodes. Shadow nodes are used primarily
|
||||
* for layouting therefore it extends {@link YogaNode} to allow that. They also help with handling
|
||||
* Common base subclass of {@link YogaNode} for all layout nodes for react-based view. It extends
|
||||
* {@link YogaNode} by adding additional capabilities.
|
||||
*
|
||||
* <p>Instances of this class receive property updates from JS via @{link UIManagerModule}.
|
||||
* Subclasses may use {@link #updateShadowNode} to persist some of the updated fields in the node
|
||||
* instance that corresponds to a particular view type.
|
||||
* Instances of this class receive property updates from JS via @{link UIManagerModule}. Subclasses
|
||||
* may use {@link #updateShadowNode} to persist some of the updated fields in the node instance that
|
||||
* corresponds to a particular view type.
|
||||
*
|
||||
* <p>Subclasses of {@link ReactShadowNode} should be created only from {@link ViewManager} that
|
||||
* Subclasses of {@link ReactShadowNode} should be created only from {@link ViewManager} that
|
||||
* corresponds to a certain type of native view. They will be updated and accessed only from JS
|
||||
* thread. Subclasses of {@link ViewManager} may choose to use base class {@link ReactShadowNode} or
|
||||
* custom subclass of it if necessary.
|
||||
*
|
||||
* <p>The primary use-case for {@link ReactShadowNode} nodes is to calculate layouting. Although
|
||||
* this might be extended. For some examples please refer to ARTGroupYogaNode or ReactTextYogaNode.
|
||||
* The primary use-case for {@link ReactShadowNode} nodes is to calculate layouting. Although this
|
||||
* might be extended. For some examples please refer to ARTGroupYogaNode or ReactTextYogaNode.
|
||||
*
|
||||
* <p>This class allows for the native view hierarchy to not be an exact copy of the hierarchy
|
||||
* received from JS by keeping track of both JS children (e.g. {@link #getChildCount()} and
|
||||
* separately native children (e.g. {@link #getNativeChildCount()}). See {@link
|
||||
* NativeViewHierarchyOptimizer} for more information.
|
||||
* This class allows for the native view hierarchy to not be an exact copy of the hierarchy received
|
||||
* from JS by keeping track of both JS children (e.g. {@link #getChildCount()} and separately native
|
||||
* children (e.g. {@link #getNativeChildCount()}). See {@link NativeViewHierarchyOptimizer} for more
|
||||
* information.
|
||||
*/
|
||||
@ReactPropertyHolder
|
||||
public interface ReactShadowNode<T extends ReactShadowNode> {
|
||||
public class ReactShadowNode {
|
||||
|
||||
private int mReactTag;
|
||||
private @Nullable String mViewClassName;
|
||||
private @Nullable ReactShadowNode mRootNode;
|
||||
private @Nullable ThemedReactContext mThemedContext;
|
||||
private boolean mShouldNotifyOnLayout;
|
||||
private boolean mNodeUpdated = true;
|
||||
private @Nullable ArrayList<ReactShadowNode> mChildren;
|
||||
private @Nullable ReactShadowNode mParent;
|
||||
|
||||
// layout-only nodes
|
||||
private boolean mIsLayoutOnly;
|
||||
private int mTotalNativeChildren = 0;
|
||||
private @Nullable ReactShadowNode mNativeParent;
|
||||
private @Nullable ArrayList<ReactShadowNode> mNativeChildren;
|
||||
private int mScreenX;
|
||||
private int mScreenY;
|
||||
private int mScreenWidth;
|
||||
private int mScreenHeight;
|
||||
private final Spacing mDefaultPadding = new Spacing(0);
|
||||
private final float[] mPadding = new float[Spacing.ALL + 1];
|
||||
private final boolean[] mPaddingIsPercent = new boolean[Spacing.ALL + 1];
|
||||
private final YogaNode mYogaNode;
|
||||
private static YogaConfig sYogaConfig;
|
||||
|
||||
public ReactShadowNode() {
|
||||
if (!isVirtual()) {
|
||||
YogaNode node = YogaNodePool.get().acquire();
|
||||
if (sYogaConfig == null) {
|
||||
sYogaConfig = new YogaConfig();
|
||||
sYogaConfig.setPointScaleFactor(0f);
|
||||
sYogaConfig.setUseLegacyStretchBehaviour(true);
|
||||
}
|
||||
if (node == null) {
|
||||
node = new YogaNode(sYogaConfig);
|
||||
}
|
||||
mYogaNode = node;
|
||||
Arrays.fill(mPadding, YogaConstants.UNDEFINED);
|
||||
} else {
|
||||
mYogaNode = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nodes that return {@code true} will be treated as "virtual" nodes. That is, nodes that are not
|
||||
* mapped into native views (e.g. nested text node). By default this method returns {@code false}.
|
||||
*/
|
||||
boolean isVirtual();
|
||||
public boolean isVirtual() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nodes that return {@code true} will be treated as a root view for the virtual nodes tree. It
|
||||
* means that {@link NativeViewHierarchyManager} will not try to perform {@code manageChildren}
|
||||
* operation on such views. Good example is {@code InputText} view that may have children {@code
|
||||
* Text} nodes but this whole hierarchy will be mapped to a single android {@link EditText} view.
|
||||
* operation on such views. Good example is {@code InputText} view that may have children
|
||||
* {@code Text} nodes but this whole hierarchy will be mapped to a single android {@link EditText}
|
||||
* view.
|
||||
*/
|
||||
boolean isVirtualAnchor();
|
||||
public boolean isVirtualAnchor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nodes that return {@code true} will not manage (and and remove) child Yoga nodes. For example
|
||||
* {@link ReactTextInputShadowNode} or {@link ReactTextShadowNode} have child nodes, which do not
|
||||
* want Yoga to lay out, so in the eyes of Yoga it is a leaf node. Override this method in
|
||||
* subclass to enforce this requirement.
|
||||
* Nodes that return {@code true} will not manage (and and remove) child Yoga nodes.
|
||||
* For example {@link ReactTextInputShadowNode} or {@link ReactTextShadowNode} have child nodes,
|
||||
* which do not want Yoga to lay out, so in the eyes of Yoga it is a leaf node.
|
||||
* Override this method in subclass to enforce this requirement.
|
||||
*/
|
||||
boolean isYogaLeafNode();
|
||||
public boolean isYogaLeafNode() {
|
||||
return isMeasureDefined();
|
||||
}
|
||||
|
||||
String getViewClass();
|
||||
public final String getViewClass() {
|
||||
return Assertions.assertNotNull(mViewClassName);
|
||||
}
|
||||
|
||||
boolean hasUpdates();
|
||||
public final boolean hasUpdates() {
|
||||
return mNodeUpdated || hasNewLayout() || isDirty();
|
||||
}
|
||||
|
||||
void markUpdateSeen();
|
||||
public final void markUpdateSeen() {
|
||||
mNodeUpdated = false;
|
||||
if (hasNewLayout()) {
|
||||
markLayoutSeen();
|
||||
}
|
||||
}
|
||||
|
||||
void markUpdated();
|
||||
public void markUpdated() {
|
||||
if (mNodeUpdated) {
|
||||
return;
|
||||
}
|
||||
mNodeUpdated = true;
|
||||
ReactShadowNode parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.markUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasUnseenUpdates();
|
||||
public final boolean hasUnseenUpdates() {
|
||||
return mNodeUpdated;
|
||||
}
|
||||
|
||||
void dirty();
|
||||
public void dirty() {
|
||||
if (!isVirtual()) {
|
||||
mYogaNode.dirty();
|
||||
}
|
||||
}
|
||||
|
||||
boolean isDirty();
|
||||
public final boolean isDirty() {
|
||||
return mYogaNode != null && mYogaNode.isDirty();
|
||||
}
|
||||
|
||||
void addChildAt(T child, int i);
|
||||
public void addChildAt(ReactShadowNode child, int i) {
|
||||
if (child.mParent != null) {
|
||||
throw new IllegalViewOperationException(
|
||||
"Tried to add child that already has a parent! Remove it from its parent first.");
|
||||
}
|
||||
if (mChildren == null) {
|
||||
mChildren = new ArrayList<ReactShadowNode>(4);
|
||||
}
|
||||
mChildren.add(i, child);
|
||||
child.mParent = this;
|
||||
|
||||
T removeChildAt(int i);
|
||||
// If a CSS node has measure defined, the layout algorithm will not visit its children. Even
|
||||
// more, it asserts that you don't add children to nodes with measure functions.
|
||||
if (mYogaNode != null && !isYogaLeafNode()) {
|
||||
YogaNode childYogaNode = child.mYogaNode;
|
||||
if (childYogaNode == null) {
|
||||
throw new RuntimeException(
|
||||
"Cannot add a child that doesn't have a YogaNode to a parent without a measure " +
|
||||
"function! (Trying to add a '" + child.getClass().getSimpleName() + "' to a '" +
|
||||
getClass().getSimpleName() + "')");
|
||||
}
|
||||
mYogaNode.addChildAt(childYogaNode, i);
|
||||
}
|
||||
markUpdated();
|
||||
|
||||
int getChildCount();
|
||||
int increase = child.mIsLayoutOnly ? child.mTotalNativeChildren : 1;
|
||||
mTotalNativeChildren += increase;
|
||||
|
||||
T getChildAt(int i);
|
||||
updateNativeChildrenCountInParent(increase);
|
||||
}
|
||||
|
||||
int indexOf(T child);
|
||||
public ReactShadowNode removeChildAt(int i) {
|
||||
if (mChildren == null) {
|
||||
throw new ArrayIndexOutOfBoundsException(
|
||||
"Index " + i + " out of bounds: node has no children");
|
||||
}
|
||||
ReactShadowNode removed = mChildren.remove(i);
|
||||
removed.mParent = null;
|
||||
|
||||
void removeAndDisposeAllChildren();
|
||||
if (mYogaNode != null && !isYogaLeafNode()) {
|
||||
mYogaNode.removeChildAt(i);
|
||||
}
|
||||
markUpdated();
|
||||
|
||||
int decrease = removed.mIsLayoutOnly ? removed.mTotalNativeChildren : 1;
|
||||
mTotalNativeChildren -= decrease;
|
||||
updateNativeChildrenCountInParent(-decrease);
|
||||
return removed;
|
||||
}
|
||||
|
||||
public final int getChildCount() {
|
||||
return mChildren == null ? 0 : mChildren.size();
|
||||
}
|
||||
|
||||
public final ReactShadowNode getChildAt(int i) {
|
||||
if (mChildren == null) {
|
||||
throw new ArrayIndexOutOfBoundsException(
|
||||
"Index " + i + " out of bounds: node has no children");
|
||||
}
|
||||
return mChildren.get(i);
|
||||
}
|
||||
|
||||
public final int indexOf(ReactShadowNode child) {
|
||||
return mChildren == null ? -1 : mChildren.indexOf(child);
|
||||
}
|
||||
|
||||
public void removeAndDisposeAllChildren() {
|
||||
if (getChildCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int decrease = 0;
|
||||
for (int i = getChildCount() - 1; i >= 0; i--) {
|
||||
if (mYogaNode != null && !isYogaLeafNode()) {
|
||||
mYogaNode.removeChildAt(i);
|
||||
}
|
||||
ReactShadowNode toRemove = getChildAt(i);
|
||||
toRemove.mParent = null;
|
||||
toRemove.dispose();
|
||||
|
||||
decrease += toRemove.mIsLayoutOnly ? toRemove.mTotalNativeChildren : 1;
|
||||
}
|
||||
Assertions.assertNotNull(mChildren).clear();
|
||||
markUpdated();
|
||||
|
||||
mTotalNativeChildren -= decrease;
|
||||
updateNativeChildrenCountInParent(-decrease);
|
||||
}
|
||||
|
||||
private void updateNativeChildrenCountInParent(int delta) {
|
||||
if (mIsLayoutOnly) {
|
||||
ReactShadowNode parent = getParent();
|
||||
while (parent != null) {
|
||||
parent.mTotalNativeChildren += delta;
|
||||
if (!parent.mIsLayoutOnly) {
|
||||
break;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called by {@link UIManagerModule} once per batch, before calculating
|
||||
* layout. Will be only called for nodes that are marked as updated with {@link #markUpdated()} or
|
||||
* require layouting (marked with {@link #dirty()}).
|
||||
* layout. Will be only called for nodes that are marked as updated with {@link #markUpdated()}
|
||||
* or require layouting (marked with {@link #dirty()}).
|
||||
*/
|
||||
void onBeforeLayout();
|
||||
public void onBeforeLayout() {
|
||||
}
|
||||
|
||||
void updateProperties(ReactStylesDiffMap props);
|
||||
public final void updateProperties(ReactStylesDiffMap props) {
|
||||
ViewManagerPropertyUpdater.updateProps(this, props);
|
||||
onAfterUpdateTransaction();
|
||||
}
|
||||
|
||||
void onAfterUpdateTransaction();
|
||||
public void onAfterUpdateTransaction() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after layout step at the end of the UI batch from {@link UIManagerModule}. May be used
|
||||
* to enqueue additional ui operations for the native view. Will only be called on nodes marked as
|
||||
* updated either with {@link #dirty()} or {@link #markUpdated()}.
|
||||
* to enqueue additional ui operations for the native view. Will only be called on nodes marked
|
||||
* as updated either with {@link #dirty()} or {@link #markUpdated()}.
|
||||
*
|
||||
* @param uiViewOperationQueue interface for enqueueing UI operations
|
||||
*/
|
||||
void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue);
|
||||
public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
|
||||
}
|
||||
|
||||
/** @return true if layout (position or dimensions) changed, false otherwise. */
|
||||
/**
|
||||
* @return true if layout (position or dimensions) changed, false otherwise.
|
||||
*/
|
||||
/* package */ boolean dispatchUpdates(
|
||||
float absoluteX,
|
||||
float absoluteY,
|
||||
UIViewOperationQueue uiViewOperationQueue,
|
||||
NativeViewHierarchyOptimizer nativeViewHierarchyOptimizer);
|
||||
NativeViewHierarchyOptimizer nativeViewHierarchyOptimizer) {
|
||||
if (mNodeUpdated) {
|
||||
onCollectExtraUpdates(uiViewOperationQueue);
|
||||
}
|
||||
|
||||
int getReactTag();
|
||||
if (hasNewLayout()) {
|
||||
float layoutX = getLayoutX();
|
||||
float layoutY = getLayoutY();
|
||||
int newAbsoluteLeft = Math.round(absoluteX + layoutX);
|
||||
int newAbsoluteTop = Math.round(absoluteY + layoutY);
|
||||
int newAbsoluteRight = Math.round(absoluteX + layoutX + getLayoutWidth());
|
||||
int newAbsoluteBottom = Math.round(absoluteY + layoutY + getLayoutHeight());
|
||||
|
||||
void setReactTag(int reactTag);
|
||||
int newScreenX = Math.round(layoutX);
|
||||
int newScreenY = Math.round(layoutY);
|
||||
int newScreenWidth = newAbsoluteRight - newAbsoluteLeft;
|
||||
int newScreenHeight = newAbsoluteBottom - newAbsoluteTop;
|
||||
|
||||
T getRootNode();
|
||||
boolean layoutHasChanged =
|
||||
newScreenX != mScreenX ||
|
||||
newScreenY != mScreenY ||
|
||||
newScreenWidth != mScreenWidth ||
|
||||
newScreenHeight != mScreenHeight;
|
||||
|
||||
void setRootNode(T rootNode);
|
||||
mScreenX = newScreenX;
|
||||
mScreenY = newScreenY;
|
||||
mScreenWidth = newScreenWidth;
|
||||
mScreenHeight = newScreenHeight;
|
||||
|
||||
void setViewClassName(String viewClassName);
|
||||
if (layoutHasChanged) {
|
||||
nativeViewHierarchyOptimizer.handleUpdateLayout(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
T getParent();
|
||||
return layoutHasChanged;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public final int getReactTag() {
|
||||
return mReactTag;
|
||||
}
|
||||
|
||||
public void setReactTag(int reactTag) {
|
||||
mReactTag = reactTag;
|
||||
}
|
||||
|
||||
public final ReactShadowNode getRootNode() {
|
||||
return Assertions.assertNotNull(mRootNode);
|
||||
}
|
||||
|
||||
/* package */ final void setRootNode(ReactShadowNode rootNode) {
|
||||
mRootNode = rootNode;
|
||||
}
|
||||
|
||||
/* package */ final void setViewClassName(String viewClassName) {
|
||||
mViewClassName = viewClassName;
|
||||
}
|
||||
|
||||
public final @Nullable ReactShadowNode getParent() {
|
||||
return mParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ThemedReactContext} associated with this {@link ReactShadowNode}. This will
|
||||
* never change during the lifetime of a {@link ReactShadowNode} instance, but different instances
|
||||
* can have different contexts; don't cache any calculations based on theme values globally.
|
||||
*/
|
||||
ThemedReactContext getThemedContext();
|
||||
public final ThemedReactContext getThemedContext() {
|
||||
return Assertions.assertNotNull(mThemedContext);
|
||||
}
|
||||
|
||||
void setThemedContext(ThemedReactContext themedContext);
|
||||
public void setThemedContext(ThemedReactContext themedContext) {
|
||||
mThemedContext = themedContext;
|
||||
}
|
||||
|
||||
boolean shouldNotifyOnLayout();
|
||||
public final boolean shouldNotifyOnLayout() {
|
||||
return mShouldNotifyOnLayout;
|
||||
}
|
||||
|
||||
void calculateLayout();
|
||||
public void calculateLayout() {
|
||||
mYogaNode.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
|
||||
}
|
||||
|
||||
boolean hasNewLayout();
|
||||
public final boolean hasNewLayout() {
|
||||
return mYogaNode != null && mYogaNode.hasNewLayout();
|
||||
}
|
||||
|
||||
void markLayoutSeen();
|
||||
public final void markLayoutSeen() {
|
||||
if (mYogaNode != null) {
|
||||
mYogaNode.markLayoutSeen();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a child that the native view hierarchy will have at this index in the native view
|
||||
* corresponding to this node.
|
||||
*/
|
||||
void addNativeChildAt(T child, int nativeIndex);
|
||||
public final void addNativeChildAt(ReactShadowNode child, int nativeIndex) {
|
||||
Assertions.assertCondition(!mIsLayoutOnly);
|
||||
Assertions.assertCondition(!child.mIsLayoutOnly);
|
||||
|
||||
T removeNativeChildAt(int i);
|
||||
if (mNativeChildren == null) {
|
||||
mNativeChildren = new ArrayList<>(4);
|
||||
}
|
||||
|
||||
void removeAllNativeChildren();
|
||||
mNativeChildren.add(nativeIndex, child);
|
||||
child.mNativeParent = this;
|
||||
}
|
||||
|
||||
int getNativeChildCount();
|
||||
public final ReactShadowNode removeNativeChildAt(int i) {
|
||||
Assertions.assertNotNull(mNativeChildren);
|
||||
ReactShadowNode removed = mNativeChildren.remove(i);
|
||||
removed.mNativeParent = null;
|
||||
return removed;
|
||||
}
|
||||
|
||||
int indexOfNativeChild(T nativeChild);
|
||||
public final void removeAllNativeChildren() {
|
||||
if (mNativeChildren != null) {
|
||||
for (int i = mNativeChildren.size() - 1; i >= 0; i--) {
|
||||
mNativeChildren.get(i).mNativeParent = null;
|
||||
}
|
||||
mNativeChildren.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
T getNativeParent();
|
||||
public final int getNativeChildCount() {
|
||||
return mNativeChildren == null ? 0 : mNativeChildren.size();
|
||||
}
|
||||
|
||||
public final int indexOfNativeChild(ReactShadowNode nativeChild) {
|
||||
Assertions.assertNotNull(mNativeChildren);
|
||||
return mNativeChildren.indexOf(nativeChild);
|
||||
}
|
||||
|
||||
public final @Nullable ReactShadowNode getNativeParent() {
|
||||
return mNativeParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this node only contributes to the layout of its children without doing any drawing
|
||||
* or functionality itself.
|
||||
* Sets whether this node only contributes to the layout of its children without doing any
|
||||
* drawing or functionality itself.
|
||||
*/
|
||||
void setIsLayoutOnly(boolean isLayoutOnly);
|
||||
public final void setIsLayoutOnly(boolean isLayoutOnly) {
|
||||
Assertions.assertCondition(getParent() == null, "Must remove from no opt parent first");
|
||||
Assertions.assertCondition(mNativeParent == null, "Must remove from native parent first");
|
||||
Assertions.assertCondition(getNativeChildCount() == 0, "Must remove all native children first");
|
||||
mIsLayoutOnly = isLayoutOnly;
|
||||
}
|
||||
|
||||
boolean isLayoutOnly();
|
||||
public final boolean isLayoutOnly() {
|
||||
return mIsLayoutOnly;
|
||||
}
|
||||
|
||||
int getTotalNativeChildren();
|
||||
public final int getTotalNativeChildren() {
|
||||
return mTotalNativeChildren;
|
||||
}
|
||||
|
||||
boolean isDescendantOf(T ancestorNode);
|
||||
public boolean isDescendantOf(ReactShadowNode ancestorNode) {
|
||||
ReactShadowNode parentNode = getParent();
|
||||
|
||||
boolean isDescendant = false;
|
||||
|
||||
while (parentNode != null) {
|
||||
if (parentNode == ancestorNode) {
|
||||
isDescendant = true;
|
||||
break;
|
||||
} else {
|
||||
parentNode = parentNode.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
return isDescendant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset within the native children owned by all layout-only nodes in the subtree
|
||||
|
@ -192,143 +488,368 @@ public interface ReactShadowNode<T extends ReactShadowNode> {
|
|||
* in this subtree (which means that the given child will be a sibling of theirs in the final
|
||||
* native hierarchy since they'll get attached to the same native parent).
|
||||
*
|
||||
* <p>Basically, a view might have children that have been optimized away by {@link
|
||||
* NativeViewHierarchyOptimizer}. Since those children will then add their native children to this
|
||||
* view, we now have ranges of native children that correspond to single unoptimized children. The
|
||||
* purpose of this method is to return the index within the native children that corresponds to
|
||||
* the **start** of the native children that belong to the given child. Also, note that all of the
|
||||
* children of a view might be optimized away, so this could return the same value for multiple
|
||||
* different children.
|
||||
* Basically, a view might have children that have been optimized away by
|
||||
* {@link NativeViewHierarchyOptimizer}. Since those children will then add their native children
|
||||
* to this view, we now have ranges of native children that correspond to single unoptimized
|
||||
* children. The purpose of this method is to return the index within the native children that
|
||||
* corresponds to the **start** of the native children that belong to the given child. Also, note
|
||||
* that all of the children of a view might be optimized away, so this could return the same value
|
||||
* for multiple different children.
|
||||
*
|
||||
* <p>Example. Native children are represented by (N) where N is the no-opt child they came from.
|
||||
* If no children are optimized away it'd look like this: (0) (1) (2) (3) ... (n)
|
||||
* Example. Native children are represented by (N) where N is the no-opt child they came from. If
|
||||
* no children are optimized away it'd look like this: (0) (1) (2) (3) ... (n)
|
||||
*
|
||||
* <p>In case some children are optimized away, it might look like this: (0) (1) (1) (1) (3) (3)
|
||||
* (4)
|
||||
* In case some children are optimized away, it might look like this:
|
||||
* (0) (1) (1) (1) (3) (3) (4)
|
||||
*
|
||||
* <p>In that case: getNativeOffsetForChild(Node 0) => 0 getNativeOffsetForChild(Node 1) => 1
|
||||
* getNativeOffsetForChild(Node 2) => 4 getNativeOffsetForChild(Node 3) => 4
|
||||
* In that case:
|
||||
* getNativeOffsetForChild(Node 0) => 0
|
||||
* getNativeOffsetForChild(Node 1) => 1
|
||||
* getNativeOffsetForChild(Node 2) => 4
|
||||
* getNativeOffsetForChild(Node 3) => 4
|
||||
* getNativeOffsetForChild(Node 4) => 6
|
||||
*/
|
||||
int getNativeOffsetForChild(T child);
|
||||
public final int getNativeOffsetForChild(ReactShadowNode child) {
|
||||
int index = 0;
|
||||
boolean found = false;
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
ReactShadowNode current = getChildAt(i);
|
||||
if (child == current) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
index += (current.mIsLayoutOnly ? current.getTotalNativeChildren() : 1);
|
||||
}
|
||||
if (!found) {
|
||||
throw new RuntimeException("Child " + child.mReactTag + " was not a child of " + mReactTag);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
float getLayoutX();
|
||||
public final float getLayoutX() {
|
||||
return mYogaNode.getLayoutX();
|
||||
}
|
||||
|
||||
float getLayoutY();
|
||||
public final float getLayoutY() {
|
||||
return mYogaNode.getLayoutY();
|
||||
}
|
||||
|
||||
float getLayoutWidth();
|
||||
public final float getLayoutWidth() {
|
||||
return mYogaNode.getLayoutWidth();
|
||||
}
|
||||
|
||||
float getLayoutHeight();
|
||||
public final float getLayoutHeight() {
|
||||
return mYogaNode.getLayoutHeight();
|
||||
}
|
||||
|
||||
/** @return the x position of the corresponding view on the screen, rounded to pixels */
|
||||
int getScreenX();
|
||||
/**
|
||||
* @return the x position of the corresponding view on the screen, rounded to pixels
|
||||
*/
|
||||
public int getScreenX() {
|
||||
return mScreenX;
|
||||
}
|
||||
|
||||
/** @return the y position of the corresponding view on the screen, rounded to pixels */
|
||||
int getScreenY();
|
||||
/**
|
||||
* @return the y position of the corresponding view on the screen, rounded to pixels
|
||||
*/
|
||||
public int getScreenY() {
|
||||
return mScreenY;
|
||||
}
|
||||
|
||||
/** @return width corrected for rounding to pixels. */
|
||||
int getScreenWidth();
|
||||
/**
|
||||
* @return width corrected for rounding to pixels.
|
||||
*/
|
||||
public int getScreenWidth() {
|
||||
return mScreenWidth;
|
||||
}
|
||||
|
||||
/** @return height corrected for rounding to pixels. */
|
||||
int getScreenHeight();
|
||||
/**
|
||||
* @return height corrected for rounding to pixels.
|
||||
*/
|
||||
public int getScreenHeight() {
|
||||
return mScreenHeight;
|
||||
}
|
||||
|
||||
YogaDirection getLayoutDirection();
|
||||
public final YogaDirection getLayoutDirection() {
|
||||
return mYogaNode.getLayoutDirection();
|
||||
}
|
||||
|
||||
void setLayoutDirection(YogaDirection direction);
|
||||
public void setLayoutDirection(YogaDirection direction) {
|
||||
mYogaNode.setDirection(direction);
|
||||
}
|
||||
|
||||
YogaValue getStyleWidth();
|
||||
public final YogaValue getStyleWidth() {
|
||||
return mYogaNode.getWidth();
|
||||
}
|
||||
|
||||
void setStyleWidth(float widthPx);
|
||||
public void setStyleWidth(float widthPx) {
|
||||
mYogaNode.setWidth(widthPx);
|
||||
}
|
||||
|
||||
void setStyleWidthPercent(float percent);
|
||||
public void setStyleWidthPercent(float percent) {
|
||||
mYogaNode.setWidthPercent(percent);
|
||||
}
|
||||
|
||||
void setStyleWidthAuto();
|
||||
public void setStyleWidthAuto() {
|
||||
mYogaNode.setWidthAuto();
|
||||
}
|
||||
|
||||
void setStyleMinWidth(float widthPx);
|
||||
public void setStyleMinWidth(float widthPx) {
|
||||
mYogaNode.setMinWidth(widthPx);
|
||||
}
|
||||
|
||||
void setStyleMinWidthPercent(float percent);
|
||||
public void setStyleMinWidthPercent(float percent) {
|
||||
mYogaNode.setMinWidthPercent(percent);
|
||||
}
|
||||
|
||||
void setStyleMaxWidth(float widthPx);
|
||||
public void setStyleMaxWidth(float widthPx) {
|
||||
mYogaNode.setMaxWidth(widthPx);
|
||||
}
|
||||
|
||||
void setStyleMaxWidthPercent(float percent);
|
||||
public void setStyleMaxWidthPercent(float percent) {
|
||||
mYogaNode.setMaxWidthPercent(percent);
|
||||
}
|
||||
|
||||
YogaValue getStyleHeight();
|
||||
public final YogaValue getStyleHeight() {
|
||||
return mYogaNode.getHeight();
|
||||
}
|
||||
|
||||
void setStyleHeight(float heightPx);
|
||||
public void setStyleHeight(float heightPx) {
|
||||
mYogaNode.setHeight(heightPx);
|
||||
}
|
||||
|
||||
void setStyleHeightPercent(float percent);
|
||||
public void setStyleHeightPercent(float percent) {
|
||||
mYogaNode.setHeightPercent(percent);
|
||||
}
|
||||
|
||||
void setStyleHeightAuto();
|
||||
public void setStyleHeightAuto() {
|
||||
mYogaNode.setHeightAuto();
|
||||
}
|
||||
|
||||
void setStyleMinHeight(float widthPx);
|
||||
public void setStyleMinHeight(float widthPx) {
|
||||
mYogaNode.setMinHeight(widthPx);
|
||||
}
|
||||
|
||||
void setStyleMinHeightPercent(float percent);
|
||||
public void setStyleMinHeightPercent(float percent) {
|
||||
mYogaNode.setMinHeightPercent(percent);
|
||||
}
|
||||
|
||||
void setStyleMaxHeight(float widthPx);
|
||||
public void setStyleMaxHeight(float widthPx) {
|
||||
mYogaNode.setMaxHeight(widthPx);
|
||||
}
|
||||
|
||||
void setStyleMaxHeightPercent(float percent);
|
||||
public void setStyleMaxHeightPercent(float percent) {
|
||||
mYogaNode.setMaxHeightPercent(percent);
|
||||
}
|
||||
|
||||
void setFlex(float flex);
|
||||
public void setFlex(float flex) {
|
||||
mYogaNode.setFlex(flex);
|
||||
}
|
||||
|
||||
void setFlexGrow(float flexGrow);
|
||||
public void setFlexGrow(float flexGrow) {
|
||||
mYogaNode.setFlexGrow(flexGrow);
|
||||
}
|
||||
|
||||
void setFlexShrink(float flexShrink);
|
||||
public void setFlexShrink(float flexShrink) {
|
||||
mYogaNode.setFlexShrink(flexShrink);
|
||||
}
|
||||
|
||||
void setFlexBasis(float flexBasis);
|
||||
public void setFlexBasis(float flexBasis) {
|
||||
mYogaNode.setFlexBasis(flexBasis);
|
||||
}
|
||||
|
||||
void setFlexBasisAuto();
|
||||
public void setFlexBasisAuto() {
|
||||
mYogaNode.setFlexBasisAuto();
|
||||
}
|
||||
|
||||
void setFlexBasisPercent(float percent);
|
||||
public void setFlexBasisPercent(float percent) {
|
||||
mYogaNode.setFlexBasisPercent(percent);
|
||||
}
|
||||
|
||||
void setStyleAspectRatio(float aspectRatio);
|
||||
public void setStyleAspectRatio(float aspectRatio) {
|
||||
mYogaNode.setAspectRatio(aspectRatio);
|
||||
}
|
||||
|
||||
void setFlexDirection(YogaFlexDirection flexDirection);
|
||||
public void setFlexDirection(YogaFlexDirection flexDirection) {
|
||||
mYogaNode.setFlexDirection(flexDirection);
|
||||
}
|
||||
|
||||
void setFlexWrap(YogaWrap wrap);
|
||||
public void setFlexWrap(YogaWrap wrap) {
|
||||
mYogaNode.setWrap(wrap);
|
||||
}
|
||||
|
||||
void setAlignSelf(YogaAlign alignSelf);
|
||||
public void setAlignSelf(YogaAlign alignSelf) {
|
||||
mYogaNode.setAlignSelf(alignSelf);
|
||||
}
|
||||
|
||||
void setAlignItems(YogaAlign alignItems);
|
||||
public void setAlignItems(YogaAlign alignItems) {
|
||||
mYogaNode.setAlignItems(alignItems);
|
||||
}
|
||||
|
||||
void setAlignContent(YogaAlign alignContent);
|
||||
public void setAlignContent(YogaAlign alignContent) {
|
||||
mYogaNode.setAlignContent(alignContent);
|
||||
}
|
||||
|
||||
void setJustifyContent(YogaJustify justifyContent);
|
||||
public void setJustifyContent(YogaJustify justifyContent) {
|
||||
mYogaNode.setJustifyContent(justifyContent);
|
||||
}
|
||||
|
||||
void setOverflow(YogaOverflow overflow);
|
||||
public void setOverflow(YogaOverflow overflow) {
|
||||
mYogaNode.setOverflow(overflow);
|
||||
}
|
||||
|
||||
void setDisplay(YogaDisplay display);
|
||||
public void setDisplay(YogaDisplay display) {
|
||||
mYogaNode.setDisplay(display);
|
||||
}
|
||||
|
||||
void setMargin(int spacingType, float margin);
|
||||
public void setMargin(int spacingType, float margin) {
|
||||
mYogaNode.setMargin(YogaEdge.fromInt(spacingType), margin);
|
||||
}
|
||||
|
||||
void setMarginPercent(int spacingType, float percent);
|
||||
public void setMarginPercent(int spacingType, float percent) {
|
||||
mYogaNode.setMarginPercent(YogaEdge.fromInt(spacingType), percent);
|
||||
}
|
||||
|
||||
void setMarginAuto(int spacingType);
|
||||
public void setMarginAuto(int spacingType) {
|
||||
mYogaNode.setMarginAuto(YogaEdge.fromInt(spacingType));
|
||||
}
|
||||
|
||||
float getPadding(int spacingType);
|
||||
public final float getPadding(int spacingType) {
|
||||
return mYogaNode.getLayoutPadding(YogaEdge.fromInt(spacingType));
|
||||
}
|
||||
|
||||
YogaValue getStylePadding(int spacingType);
|
||||
public final YogaValue getStylePadding(int spacingType) {
|
||||
return mYogaNode.getPadding(YogaEdge.fromInt(spacingType));
|
||||
}
|
||||
|
||||
void setDefaultPadding(int spacingType, float padding);
|
||||
public void setDefaultPadding(int spacingType, float padding) {
|
||||
mDefaultPadding.set(spacingType, padding);
|
||||
updatePadding();
|
||||
}
|
||||
|
||||
void setPadding(int spacingType, float padding);
|
||||
public void setPadding(int spacingType, float padding) {
|
||||
mPadding[spacingType] = padding;
|
||||
mPaddingIsPercent[spacingType] = false;
|
||||
updatePadding();
|
||||
}
|
||||
|
||||
void setPaddingPercent(int spacingType, float percent);
|
||||
public void setPaddingPercent(int spacingType, float percent) {
|
||||
mPadding[spacingType] = percent;
|
||||
mPaddingIsPercent[spacingType] = !YogaConstants.isUndefined(percent);
|
||||
updatePadding();
|
||||
}
|
||||
|
||||
void setBorder(int spacingType, float borderWidth);
|
||||
private void updatePadding() {
|
||||
for (int spacingType = Spacing.LEFT; spacingType <= Spacing.ALL; spacingType++) {
|
||||
if (spacingType == Spacing.LEFT ||
|
||||
spacingType == Spacing.RIGHT ||
|
||||
spacingType == Spacing.START ||
|
||||
spacingType == Spacing.END) {
|
||||
if (YogaConstants.isUndefined(mPadding[spacingType]) &&
|
||||
YogaConstants.isUndefined(mPadding[Spacing.HORIZONTAL]) &&
|
||||
YogaConstants.isUndefined(mPadding[Spacing.ALL])) {
|
||||
mYogaNode.setPadding(YogaEdge.fromInt(spacingType), mDefaultPadding.getRaw(spacingType));
|
||||
continue;
|
||||
}
|
||||
} else if (spacingType == Spacing.TOP || spacingType == Spacing.BOTTOM) {
|
||||
if (YogaConstants.isUndefined(mPadding[spacingType]) &&
|
||||
YogaConstants.isUndefined(mPadding[Spacing.VERTICAL]) &&
|
||||
YogaConstants.isUndefined(mPadding[Spacing.ALL])) {
|
||||
mYogaNode.setPadding(YogaEdge.fromInt(spacingType), mDefaultPadding.getRaw(spacingType));
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (YogaConstants.isUndefined(mPadding[spacingType])) {
|
||||
mYogaNode.setPadding(YogaEdge.fromInt(spacingType), mDefaultPadding.getRaw(spacingType));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
void setPosition(int spacingType, float position);
|
||||
if (mPaddingIsPercent[spacingType]) {
|
||||
mYogaNode.setPaddingPercent(YogaEdge.fromInt(spacingType), mPadding[spacingType]);
|
||||
} else {
|
||||
mYogaNode.setPadding(YogaEdge.fromInt(spacingType), mPadding[spacingType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setPositionPercent(int spacingType, float percent);
|
||||
public void setBorder(int spacingType, float borderWidth) {
|
||||
mYogaNode.setBorder(YogaEdge.fromInt(spacingType), borderWidth);
|
||||
}
|
||||
|
||||
void setPositionType(YogaPositionType positionType);
|
||||
public void setPosition(int spacingType, float position) {
|
||||
mYogaNode.setPosition(YogaEdge.fromInt(spacingType), position);
|
||||
}
|
||||
|
||||
void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout);
|
||||
public void setPositionPercent(int spacingType, float percent) {
|
||||
mYogaNode.setPositionPercent(YogaEdge.fromInt(spacingType), percent);
|
||||
}
|
||||
|
||||
void setBaselineFunction(YogaBaselineFunction baselineFunction);
|
||||
public void setPositionType(YogaPositionType positionType) {
|
||||
mYogaNode.setPositionType(positionType);
|
||||
}
|
||||
|
||||
void setMeasureFunction(YogaMeasureFunction measureFunction);
|
||||
public void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout) {
|
||||
mShouldNotifyOnLayout = shouldNotifyOnLayout;
|
||||
}
|
||||
|
||||
boolean isMeasureDefined();
|
||||
public void setBaselineFunction(YogaBaselineFunction baselineFunction) {
|
||||
mYogaNode.setBaselineFunction(baselineFunction);
|
||||
}
|
||||
|
||||
void dispose();
|
||||
public void setMeasureFunction(YogaMeasureFunction measureFunction) {
|
||||
if ((measureFunction == null ^ mYogaNode.isMeasureDefined()) &&
|
||||
getChildCount() != 0) {
|
||||
throw new RuntimeException(
|
||||
"Since a node with a measure function does not add any native yoga children, it's " +
|
||||
"not safe to transition to/from having a measure function unless a node has no children");
|
||||
}
|
||||
mYogaNode.setMeasureFunction(measureFunction);
|
||||
}
|
||||
|
||||
public boolean isMeasureDefined() {
|
||||
return mYogaNode.isMeasureDefined();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
toStringWithIndentation(sb, 0);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void toStringWithIndentation(StringBuilder result, int level) {
|
||||
// Spaces and tabs are dropped by IntelliJ logcat integration, so rely on __ instead.
|
||||
for (int i = 0; i < level; ++i) {
|
||||
result.append("__");
|
||||
}
|
||||
|
||||
result
|
||||
.append(getClass().getSimpleName())
|
||||
.append(" ");
|
||||
if (mYogaNode != null) {
|
||||
result
|
||||
.append(getLayoutWidth())
|
||||
.append(",")
|
||||
.append(getLayoutHeight());
|
||||
} else {
|
||||
result.append("(virtual node)");
|
||||
}
|
||||
result.append("\n");
|
||||
|
||||
if (getChildCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
getChildAt(i).toStringWithIndentation(result, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (mYogaNode != null) {
|
||||
mYogaNode.reset();
|
||||
YogaNodePool.get().release(mYogaNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,940 +0,0 @@
|
|||
/**
|
||||
* 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.uimanager;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.yoga.YogaAlign;
|
||||
import com.facebook.yoga.YogaBaselineFunction;
|
||||
import com.facebook.yoga.YogaConfig;
|
||||
import com.facebook.yoga.YogaConstants;
|
||||
import com.facebook.yoga.YogaDirection;
|
||||
import com.facebook.yoga.YogaDisplay;
|
||||
import com.facebook.yoga.YogaEdge;
|
||||
import com.facebook.yoga.YogaFlexDirection;
|
||||
import com.facebook.yoga.YogaJustify;
|
||||
import com.facebook.yoga.YogaMeasureFunction;
|
||||
import com.facebook.yoga.YogaNode;
|
||||
import com.facebook.yoga.YogaOverflow;
|
||||
import com.facebook.yoga.YogaPositionType;
|
||||
import com.facebook.yoga.YogaValue;
|
||||
import com.facebook.yoga.YogaWrap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Base node class for representing virtual tree of React nodes. Shadow nodes are used primarily for
|
||||
* layouting therefore it extends {@link YogaNode} to allow that. They also help with handling
|
||||
* Common base subclass of {@link YogaNode} for all layout nodes for react-based view. It extends
|
||||
* {@link YogaNode} by adding additional capabilities.
|
||||
*
|
||||
* <p>Instances of this class receive property updates from JS via @{link UIManagerModule}.
|
||||
* Subclasses may use {@link #updateShadowNode} to persist some of the updated fields in the node
|
||||
* instance that corresponds to a particular view type.
|
||||
*
|
||||
* <p>Subclasses of {@link ReactShadowNodeImpl} should be created only from {@link ViewManager} that
|
||||
* corresponds to a certain type of native view. They will be updated and accessed only from JS
|
||||
* thread. Subclasses of {@link ViewManager} may choose to use base class {@link
|
||||
* ReactShadowNodeImpl} or custom subclass of it if necessary.
|
||||
*
|
||||
* <p>The primary use-case for {@link ReactShadowNodeImpl} nodes is to calculate layouting. Although
|
||||
* this might be extended. For some examples please refer to ARTGroupYogaNode or ReactTextYogaNode.
|
||||
*
|
||||
* <p>This class allows for the native view hierarchy to not be an exact copy of the hierarchy
|
||||
* received from JS by keeping track of both JS children (e.g. {@link #getChildCount()} and
|
||||
* separately native children (e.g. {@link #getNativeChildCount()}). See {@link
|
||||
* NativeViewHierarchyOptimizer} for more information.
|
||||
*/
|
||||
public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl> {
|
||||
|
||||
private int mReactTag;
|
||||
private @Nullable String mViewClassName;
|
||||
private @Nullable ReactShadowNodeImpl mRootNode;
|
||||
private @Nullable ThemedReactContext mThemedContext;
|
||||
private boolean mShouldNotifyOnLayout;
|
||||
private boolean mNodeUpdated = true;
|
||||
private @Nullable ArrayList<ReactShadowNodeImpl> mChildren;
|
||||
private @Nullable ReactShadowNodeImpl mParent;
|
||||
|
||||
// layout-only nodes
|
||||
private boolean mIsLayoutOnly;
|
||||
private int mTotalNativeChildren = 0;
|
||||
private @Nullable ReactShadowNodeImpl mNativeParent;
|
||||
private @Nullable ArrayList<ReactShadowNodeImpl> mNativeChildren;
|
||||
private int mScreenX;
|
||||
private int mScreenY;
|
||||
private int mScreenWidth;
|
||||
private int mScreenHeight;
|
||||
private final Spacing mDefaultPadding = new Spacing(0);
|
||||
private final float[] mPadding = new float[Spacing.ALL + 1];
|
||||
private final boolean[] mPaddingIsPercent = new boolean[Spacing.ALL + 1];
|
||||
private final YogaNode mYogaNode;
|
||||
private static YogaConfig sYogaConfig;
|
||||
|
||||
public ReactShadowNodeImpl() {
|
||||
if (!isVirtual()) {
|
||||
YogaNode node = YogaNodePool.get().acquire();
|
||||
if (sYogaConfig == null) {
|
||||
sYogaConfig = new YogaConfig();
|
||||
sYogaConfig.setPointScaleFactor(0f);
|
||||
sYogaConfig.setUseLegacyStretchBehaviour(true);
|
||||
}
|
||||
if (node == null) {
|
||||
node = new YogaNode(sYogaConfig);
|
||||
}
|
||||
mYogaNode = node;
|
||||
Arrays.fill(mPadding, YogaConstants.UNDEFINED);
|
||||
} else {
|
||||
mYogaNode = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nodes that return {@code true} will be treated as "virtual" nodes. That is, nodes that are not
|
||||
* mapped into native views (e.g. nested text node). By default this method returns {@code false}.
|
||||
*/
|
||||
@Override
|
||||
public boolean isVirtual() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nodes that return {@code true} will be treated as a root view for the virtual nodes tree. It
|
||||
* means that {@link NativeViewHierarchyManager} will not try to perform {@code manageChildren}
|
||||
* operation on such views. Good example is {@code InputText} view that may have children {@code
|
||||
* Text} nodes but this whole hierarchy will be mapped to a single android {@link EditText} view.
|
||||
*/
|
||||
@Override
|
||||
public boolean isVirtualAnchor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nodes that return {@code true} will not manage (and and remove) child Yoga nodes. For example
|
||||
* {@link ReactTextInputShadowNode} or {@link ReactTextShadowNode} have child nodes, which do not
|
||||
* want Yoga to lay out, so in the eyes of Yoga it is a leaf node. Override this method in
|
||||
* subclass to enforce this requirement.
|
||||
*/
|
||||
@Override
|
||||
public boolean isYogaLeafNode() {
|
||||
return isMeasureDefined();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getViewClass() {
|
||||
return Assertions.assertNotNull(mViewClassName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasUpdates() {
|
||||
return mNodeUpdated || hasNewLayout() || isDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void markUpdateSeen() {
|
||||
mNodeUpdated = false;
|
||||
if (hasNewLayout()) {
|
||||
markLayoutSeen();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markUpdated() {
|
||||
if (mNodeUpdated) {
|
||||
return;
|
||||
}
|
||||
mNodeUpdated = true;
|
||||
ReactShadowNodeImpl parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.markUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasUnseenUpdates() {
|
||||
return mNodeUpdated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dirty() {
|
||||
if (!isVirtual()) {
|
||||
mYogaNode.dirty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isDirty() {
|
||||
return mYogaNode != null && mYogaNode.isDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChildAt(ReactShadowNodeImpl child, int i) {
|
||||
if (child.getParent() != null) {
|
||||
throw new IllegalViewOperationException(
|
||||
"Tried to add child that already has a parent! Remove it from its parent first.");
|
||||
}
|
||||
if (mChildren == null) {
|
||||
mChildren = new ArrayList<ReactShadowNodeImpl>(4);
|
||||
}
|
||||
mChildren.add(i, child);
|
||||
child.mParent = this;
|
||||
|
||||
// If a CSS node has measure defined, the layout algorithm will not visit its children. Even
|
||||
// more, it asserts that you don't add children to nodes with measure functions.
|
||||
if (mYogaNode != null && !isYogaLeafNode()) {
|
||||
YogaNode childYogaNode = child.mYogaNode;
|
||||
if (childYogaNode == null) {
|
||||
throw new RuntimeException(
|
||||
"Cannot add a child that doesn't have a YogaNode to a parent without a measure " +
|
||||
"function! (Trying to add a '" + child.getClass().getSimpleName() + "' to a '" +
|
||||
getClass().getSimpleName() + "')");
|
||||
}
|
||||
mYogaNode.addChildAt(childYogaNode, i);
|
||||
}
|
||||
markUpdated();
|
||||
|
||||
int increase = child.isLayoutOnly() ? child.getTotalNativeChildren() : 1;
|
||||
mTotalNativeChildren += increase;
|
||||
|
||||
updateNativeChildrenCountInParent(increase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactShadowNodeImpl removeChildAt(int i) {
|
||||
if (mChildren == null) {
|
||||
throw new ArrayIndexOutOfBoundsException(
|
||||
"Index " + i + " out of bounds: node has no children");
|
||||
}
|
||||
ReactShadowNodeImpl removed = mChildren.remove(i);
|
||||
removed.mParent = null;
|
||||
|
||||
if (mYogaNode != null && !isYogaLeafNode()) {
|
||||
mYogaNode.removeChildAt(i);
|
||||
}
|
||||
markUpdated();
|
||||
|
||||
int decrease = removed.isLayoutOnly() ? removed.getTotalNativeChildren() : 1;
|
||||
mTotalNativeChildren -= decrease;
|
||||
updateNativeChildrenCountInParent(-decrease);
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getChildCount() {
|
||||
return mChildren == null ? 0 : mChildren.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ReactShadowNodeImpl getChildAt(int i) {
|
||||
if (mChildren == null) {
|
||||
throw new ArrayIndexOutOfBoundsException(
|
||||
"Index " + i + " out of bounds: node has no children");
|
||||
}
|
||||
return mChildren.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int indexOf(ReactShadowNodeImpl child) {
|
||||
return mChildren == null ? -1 : mChildren.indexOf(child);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAndDisposeAllChildren() {
|
||||
if (getChildCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int decrease = 0;
|
||||
for (int i = getChildCount() - 1; i >= 0; i--) {
|
||||
if (mYogaNode != null && !isYogaLeafNode()) {
|
||||
mYogaNode.removeChildAt(i);
|
||||
}
|
||||
ReactShadowNodeImpl toRemove = getChildAt(i);
|
||||
toRemove.mParent = null;
|
||||
toRemove.dispose();
|
||||
|
||||
decrease += toRemove.isLayoutOnly() ? toRemove.getTotalNativeChildren() : 1;
|
||||
}
|
||||
Assertions.assertNotNull(mChildren).clear();
|
||||
markUpdated();
|
||||
|
||||
mTotalNativeChildren -= decrease;
|
||||
updateNativeChildrenCountInParent(-decrease);
|
||||
}
|
||||
|
||||
private void updateNativeChildrenCountInParent(int delta) {
|
||||
if (mIsLayoutOnly) {
|
||||
ReactShadowNodeImpl parent = getParent();
|
||||
while (parent != null) {
|
||||
parent.mTotalNativeChildren += delta;
|
||||
if (!parent.isLayoutOnly()) {
|
||||
break;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called by {@link UIManagerModule} once per batch, before calculating
|
||||
* layout. Will be only called for nodes that are marked as updated with {@link #markUpdated()} or
|
||||
* require layouting (marked with {@link #dirty()}).
|
||||
*/
|
||||
@Override
|
||||
public void onBeforeLayout() {}
|
||||
|
||||
@Override
|
||||
public final void updateProperties(ReactStylesDiffMap props) {
|
||||
ViewManagerPropertyUpdater.updateProps(this, props);
|
||||
onAfterUpdateTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterUpdateTransaction() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after layout step at the end of the UI batch from {@link UIManagerModule}. May be used
|
||||
* to enqueue additional ui operations for the native view. Will only be called on nodes marked as
|
||||
* updated either with {@link #dirty()} or {@link #markUpdated()}.
|
||||
*
|
||||
* @param uiViewOperationQueue interface for enqueueing UI operations
|
||||
*/
|
||||
@Override
|
||||
public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {}
|
||||
|
||||
/** @return true if layout (position or dimensions) changed, false otherwise. */
|
||||
@Override
|
||||
public boolean dispatchUpdates(
|
||||
float absoluteX,
|
||||
float absoluteY,
|
||||
UIViewOperationQueue uiViewOperationQueue,
|
||||
NativeViewHierarchyOptimizer nativeViewHierarchyOptimizer) {
|
||||
if (mNodeUpdated) {
|
||||
onCollectExtraUpdates(uiViewOperationQueue);
|
||||
}
|
||||
|
||||
if (hasNewLayout()) {
|
||||
float layoutX = getLayoutX();
|
||||
float layoutY = getLayoutY();
|
||||
int newAbsoluteLeft = Math.round(absoluteX + layoutX);
|
||||
int newAbsoluteTop = Math.round(absoluteY + layoutY);
|
||||
int newAbsoluteRight = Math.round(absoluteX + layoutX + getLayoutWidth());
|
||||
int newAbsoluteBottom = Math.round(absoluteY + layoutY + getLayoutHeight());
|
||||
|
||||
int newScreenX = Math.round(layoutX);
|
||||
int newScreenY = Math.round(layoutY);
|
||||
int newScreenWidth = newAbsoluteRight - newAbsoluteLeft;
|
||||
int newScreenHeight = newAbsoluteBottom - newAbsoluteTop;
|
||||
|
||||
boolean layoutHasChanged =
|
||||
newScreenX != mScreenX ||
|
||||
newScreenY != mScreenY ||
|
||||
newScreenWidth != mScreenWidth ||
|
||||
newScreenHeight != mScreenHeight;
|
||||
|
||||
mScreenX = newScreenX;
|
||||
mScreenY = newScreenY;
|
||||
mScreenWidth = newScreenWidth;
|
||||
mScreenHeight = newScreenHeight;
|
||||
|
||||
if (layoutHasChanged) {
|
||||
nativeViewHierarchyOptimizer.handleUpdateLayout(this);
|
||||
}
|
||||
|
||||
return layoutHasChanged;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getReactTag() {
|
||||
return mReactTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReactTag(int reactTag) {
|
||||
mReactTag = reactTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ReactShadowNodeImpl getRootNode() {
|
||||
return Assertions.assertNotNull(mRootNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setRootNode(ReactShadowNodeImpl rootNode) {
|
||||
mRootNode = rootNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setViewClassName(String viewClassName) {
|
||||
mViewClassName = viewClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @Nullable ReactShadowNodeImpl getParent() {
|
||||
return mParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ThemedReactContext} associated with this {@link ReactShadowNodeImpl}. This will
|
||||
* never change during the lifetime of a {@link ReactShadowNodeImpl} instance, but different
|
||||
* instances can have different contexts; don't cache any calculations based on theme values
|
||||
* globally.
|
||||
*/
|
||||
@Override
|
||||
public final ThemedReactContext getThemedContext() {
|
||||
return Assertions.assertNotNull(mThemedContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThemedContext(ThemedReactContext themedContext) {
|
||||
mThemedContext = themedContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean shouldNotifyOnLayout() {
|
||||
return mShouldNotifyOnLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculateLayout() {
|
||||
mYogaNode.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasNewLayout() {
|
||||
return mYogaNode != null && mYogaNode.hasNewLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void markLayoutSeen() {
|
||||
if (mYogaNode != null) {
|
||||
mYogaNode.markLayoutSeen();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a child that the native view hierarchy will have at this index in the native view
|
||||
* corresponding to this node.
|
||||
*/
|
||||
@Override
|
||||
public final void addNativeChildAt(ReactShadowNodeImpl child, int nativeIndex) {
|
||||
Assertions.assertCondition(!mIsLayoutOnly);
|
||||
Assertions.assertCondition(!child.mIsLayoutOnly);
|
||||
|
||||
if (mNativeChildren == null) {
|
||||
mNativeChildren = new ArrayList<>(4);
|
||||
}
|
||||
|
||||
mNativeChildren.add(nativeIndex, child);
|
||||
child.mNativeParent = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ReactShadowNodeImpl removeNativeChildAt(int i) {
|
||||
Assertions.assertNotNull(mNativeChildren);
|
||||
ReactShadowNodeImpl removed = mNativeChildren.remove(i);
|
||||
removed.mNativeParent = null;
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void removeAllNativeChildren() {
|
||||
if (mNativeChildren != null) {
|
||||
for (int i = mNativeChildren.size() - 1; i >= 0; i--) {
|
||||
mNativeChildren.get(i).mNativeParent = null;
|
||||
}
|
||||
mNativeChildren.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getNativeChildCount() {
|
||||
return mNativeChildren == null ? 0 : mNativeChildren.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int indexOfNativeChild(ReactShadowNodeImpl nativeChild) {
|
||||
Assertions.assertNotNull(mNativeChildren);
|
||||
return mNativeChildren.indexOf(nativeChild);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @Nullable ReactShadowNodeImpl getNativeParent() {
|
||||
return mNativeParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this node only contributes to the layout of its children without doing any drawing
|
||||
* or functionality itself.
|
||||
*/
|
||||
@Override
|
||||
public final void setIsLayoutOnly(boolean isLayoutOnly) {
|
||||
Assertions.assertCondition(getParent() == null, "Must remove from no opt parent first");
|
||||
Assertions.assertCondition(mNativeParent == null, "Must remove from native parent first");
|
||||
Assertions.assertCondition(getNativeChildCount() == 0, "Must remove all native children first");
|
||||
mIsLayoutOnly = isLayoutOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isLayoutOnly() {
|
||||
return mIsLayoutOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getTotalNativeChildren() {
|
||||
return mTotalNativeChildren;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isDescendantOf(ReactShadowNodeImpl ancestorNode) {
|
||||
ReactShadowNodeImpl parentNode = getParent();
|
||||
|
||||
boolean isDescendant = false;
|
||||
|
||||
while (parentNode != null) {
|
||||
if (parentNode == ancestorNode) {
|
||||
isDescendant = true;
|
||||
break;
|
||||
} else {
|
||||
parentNode = parentNode.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
return isDescendant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset within the native children owned by all layout-only nodes in the subtree
|
||||
* rooted at this node for the given child. Put another way, this returns the number of native
|
||||
* nodes (nodes not optimized out of the native tree) that are a) to the left (visited before by a
|
||||
* DFS) of the given child in the subtree rooted at this node and b) do not have a native parent
|
||||
* in this subtree (which means that the given child will be a sibling of theirs in the final
|
||||
* native hierarchy since they'll get attached to the same native parent).
|
||||
*
|
||||
* <p>Basically, a view might have children that have been optimized away by {@link
|
||||
* NativeViewHierarchyOptimizer}. Since those children will then add their native children to this
|
||||
* view, we now have ranges of native children that correspond to single unoptimized children. The
|
||||
* purpose of this method is to return the index within the native children that corresponds to
|
||||
* the **start** of the native children that belong to the given child. Also, note that all of the
|
||||
* children of a view might be optimized away, so this could return the same value for multiple
|
||||
* different children.
|
||||
*
|
||||
* <p>Example. Native children are represented by (N) where N is the no-opt child they came from.
|
||||
* If no children are optimized away it'd look like this: (0) (1) (2) (3) ... (n)
|
||||
*
|
||||
* <p>In case some children are optimized away, it might look like this: (0) (1) (1) (1) (3) (3)
|
||||
* (4)
|
||||
*
|
||||
* <p>In that case: getNativeOffsetForChild(Node 0) => 0 getNativeOffsetForChild(Node 1) => 1
|
||||
* getNativeOffsetForChild(Node 2) => 4 getNativeOffsetForChild(Node 3) => 4
|
||||
* getNativeOffsetForChild(Node 4) => 6
|
||||
*/
|
||||
@Override
|
||||
public final int getNativeOffsetForChild(ReactShadowNodeImpl child) {
|
||||
int index = 0;
|
||||
boolean found = false;
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
ReactShadowNodeImpl current = getChildAt(i);
|
||||
if (child == current) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
index += (current.isLayoutOnly() ? current.getTotalNativeChildren() : 1);
|
||||
}
|
||||
if (!found) {
|
||||
throw new RuntimeException(
|
||||
"Child " + child.getReactTag() + " was not a child of " + mReactTag);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final float getLayoutX() {
|
||||
return mYogaNode.getLayoutX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final float getLayoutY() {
|
||||
return mYogaNode.getLayoutY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final float getLayoutWidth() {
|
||||
return mYogaNode.getLayoutWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final float getLayoutHeight() {
|
||||
return mYogaNode.getLayoutHeight();
|
||||
}
|
||||
|
||||
/** @return the x position of the corresponding view on the screen, rounded to pixels */
|
||||
@Override
|
||||
public int getScreenX() {
|
||||
return mScreenX;
|
||||
}
|
||||
|
||||
/** @return the y position of the corresponding view on the screen, rounded to pixels */
|
||||
@Override
|
||||
public int getScreenY() {
|
||||
return mScreenY;
|
||||
}
|
||||
|
||||
/** @return width corrected for rounding to pixels. */
|
||||
@Override
|
||||
public int getScreenWidth() {
|
||||
return mScreenWidth;
|
||||
}
|
||||
|
||||
/** @return height corrected for rounding to pixels. */
|
||||
@Override
|
||||
public int getScreenHeight() {
|
||||
return mScreenHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final YogaDirection getLayoutDirection() {
|
||||
return mYogaNode.getLayoutDirection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutDirection(YogaDirection direction) {
|
||||
mYogaNode.setDirection(direction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final YogaValue getStyleWidth() {
|
||||
return mYogaNode.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleWidth(float widthPx) {
|
||||
mYogaNode.setWidth(widthPx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleWidthPercent(float percent) {
|
||||
mYogaNode.setWidthPercent(percent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleWidthAuto() {
|
||||
mYogaNode.setWidthAuto();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleMinWidth(float widthPx) {
|
||||
mYogaNode.setMinWidth(widthPx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleMinWidthPercent(float percent) {
|
||||
mYogaNode.setMinWidthPercent(percent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleMaxWidth(float widthPx) {
|
||||
mYogaNode.setMaxWidth(widthPx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleMaxWidthPercent(float percent) {
|
||||
mYogaNode.setMaxWidthPercent(percent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final YogaValue getStyleHeight() {
|
||||
return mYogaNode.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleHeight(float heightPx) {
|
||||
mYogaNode.setHeight(heightPx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleHeightPercent(float percent) {
|
||||
mYogaNode.setHeightPercent(percent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleHeightAuto() {
|
||||
mYogaNode.setHeightAuto();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleMinHeight(float widthPx) {
|
||||
mYogaNode.setMinHeight(widthPx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleMinHeightPercent(float percent) {
|
||||
mYogaNode.setMinHeightPercent(percent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleMaxHeight(float widthPx) {
|
||||
mYogaNode.setMaxHeight(widthPx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleMaxHeightPercent(float percent) {
|
||||
mYogaNode.setMaxHeightPercent(percent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlex(float flex) {
|
||||
mYogaNode.setFlex(flex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlexGrow(float flexGrow) {
|
||||
mYogaNode.setFlexGrow(flexGrow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlexShrink(float flexShrink) {
|
||||
mYogaNode.setFlexShrink(flexShrink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlexBasis(float flexBasis) {
|
||||
mYogaNode.setFlexBasis(flexBasis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlexBasisAuto() {
|
||||
mYogaNode.setFlexBasisAuto();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlexBasisPercent(float percent) {
|
||||
mYogaNode.setFlexBasisPercent(percent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyleAspectRatio(float aspectRatio) {
|
||||
mYogaNode.setAspectRatio(aspectRatio);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlexDirection(YogaFlexDirection flexDirection) {
|
||||
mYogaNode.setFlexDirection(flexDirection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlexWrap(YogaWrap wrap) {
|
||||
mYogaNode.setWrap(wrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlignSelf(YogaAlign alignSelf) {
|
||||
mYogaNode.setAlignSelf(alignSelf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlignItems(YogaAlign alignItems) {
|
||||
mYogaNode.setAlignItems(alignItems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlignContent(YogaAlign alignContent) {
|
||||
mYogaNode.setAlignContent(alignContent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJustifyContent(YogaJustify justifyContent) {
|
||||
mYogaNode.setJustifyContent(justifyContent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOverflow(YogaOverflow overflow) {
|
||||
mYogaNode.setOverflow(overflow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplay(YogaDisplay display) {
|
||||
mYogaNode.setDisplay(display);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMargin(int spacingType, float margin) {
|
||||
mYogaNode.setMargin(YogaEdge.fromInt(spacingType), margin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarginPercent(int spacingType, float percent) {
|
||||
mYogaNode.setMarginPercent(YogaEdge.fromInt(spacingType), percent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarginAuto(int spacingType) {
|
||||
mYogaNode.setMarginAuto(YogaEdge.fromInt(spacingType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final float getPadding(int spacingType) {
|
||||
return mYogaNode.getLayoutPadding(YogaEdge.fromInt(spacingType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final YogaValue getStylePadding(int spacingType) {
|
||||
return mYogaNode.getPadding(YogaEdge.fromInt(spacingType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultPadding(int spacingType, float padding) {
|
||||
mDefaultPadding.set(spacingType, padding);
|
||||
updatePadding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPadding(int spacingType, float padding) {
|
||||
mPadding[spacingType] = padding;
|
||||
mPaddingIsPercent[spacingType] = false;
|
||||
updatePadding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPaddingPercent(int spacingType, float percent) {
|
||||
mPadding[spacingType] = percent;
|
||||
mPaddingIsPercent[spacingType] = !YogaConstants.isUndefined(percent);
|
||||
updatePadding();
|
||||
}
|
||||
|
||||
private void updatePadding() {
|
||||
for (int spacingType = Spacing.LEFT; spacingType <= Spacing.ALL; spacingType++) {
|
||||
if (spacingType == Spacing.LEFT ||
|
||||
spacingType == Spacing.RIGHT ||
|
||||
spacingType == Spacing.START ||
|
||||
spacingType == Spacing.END) {
|
||||
if (YogaConstants.isUndefined(mPadding[spacingType]) &&
|
||||
YogaConstants.isUndefined(mPadding[Spacing.HORIZONTAL]) &&
|
||||
YogaConstants.isUndefined(mPadding[Spacing.ALL])) {
|
||||
mYogaNode.setPadding(YogaEdge.fromInt(spacingType), mDefaultPadding.getRaw(spacingType));
|
||||
continue;
|
||||
}
|
||||
} else if (spacingType == Spacing.TOP || spacingType == Spacing.BOTTOM) {
|
||||
if (YogaConstants.isUndefined(mPadding[spacingType]) &&
|
||||
YogaConstants.isUndefined(mPadding[Spacing.VERTICAL]) &&
|
||||
YogaConstants.isUndefined(mPadding[Spacing.ALL])) {
|
||||
mYogaNode.setPadding(YogaEdge.fromInt(spacingType), mDefaultPadding.getRaw(spacingType));
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (YogaConstants.isUndefined(mPadding[spacingType])) {
|
||||
mYogaNode.setPadding(YogaEdge.fromInt(spacingType), mDefaultPadding.getRaw(spacingType));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (mPaddingIsPercent[spacingType]) {
|
||||
mYogaNode.setPaddingPercent(YogaEdge.fromInt(spacingType), mPadding[spacingType]);
|
||||
} else {
|
||||
mYogaNode.setPadding(YogaEdge.fromInt(spacingType), mPadding[spacingType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBorder(int spacingType, float borderWidth) {
|
||||
mYogaNode.setBorder(YogaEdge.fromInt(spacingType), borderWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPosition(int spacingType, float position) {
|
||||
mYogaNode.setPosition(YogaEdge.fromInt(spacingType), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPositionPercent(int spacingType, float percent) {
|
||||
mYogaNode.setPositionPercent(YogaEdge.fromInt(spacingType), percent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPositionType(YogaPositionType positionType) {
|
||||
mYogaNode.setPositionType(positionType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout) {
|
||||
mShouldNotifyOnLayout = shouldNotifyOnLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBaselineFunction(YogaBaselineFunction baselineFunction) {
|
||||
mYogaNode.setBaselineFunction(baselineFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMeasureFunction(YogaMeasureFunction measureFunction) {
|
||||
if ((measureFunction == null ^ mYogaNode.isMeasureDefined()) &&
|
||||
getChildCount() != 0) {
|
||||
throw new RuntimeException(
|
||||
"Since a node with a measure function does not add any native yoga children, it's " +
|
||||
"not safe to transition to/from having a measure function unless a node has no children");
|
||||
}
|
||||
mYogaNode.setMeasureFunction(measureFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMeasureDefined() {
|
||||
return mYogaNode.isMeasureDefined();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
toStringWithIndentation(sb, 0);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void toStringWithIndentation(StringBuilder result, int level) {
|
||||
// Spaces and tabs are dropped by IntelliJ logcat integration, so rely on __ instead.
|
||||
for (int i = 0; i < level; ++i) {
|
||||
result.append("__");
|
||||
}
|
||||
|
||||
result
|
||||
.append(getClass().getSimpleName())
|
||||
.append(" ");
|
||||
if (mYogaNode != null) {
|
||||
result
|
||||
.append(getLayoutWidth())
|
||||
.append(",")
|
||||
.append(getLayoutHeight());
|
||||
} else {
|
||||
result.append("(virtual node)");
|
||||
}
|
||||
result.append("\n");
|
||||
|
||||
if (getChildCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
getChildAt(i).toStringWithIndentation(result, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (mYogaNode != null) {
|
||||
mYogaNode.reset();
|
||||
YogaNodePool.get().release(mYogaNode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -97,7 +97,7 @@ public class UIImplementation {
|
|||
}
|
||||
|
||||
protected ReactShadowNode createRootShadowNode() {
|
||||
ReactShadowNode rootCSSNode = new ReactShadowNodeImpl();
|
||||
ReactShadowNode rootCSSNode = new ReactShadowNode();
|
||||
I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
|
||||
if (sharedI18nUtilInstance.isRTL(mReactContext)) {
|
||||
rootCSSNode.setLayoutDirection(YogaDirection.RTL);
|
||||
|
|
|
@ -2,7 +2,15 @@
|
|||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.react.bridge.Dynamic;
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
|
@ -10,11 +18,6 @@ import com.facebook.react.bridge.ReadableArray;
|
|||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* This class is responsible for holding view manager property setters and is used in a process of
|
||||
|
@ -330,7 +333,7 @@ import javax.annotation.Nullable;
|
|||
*/
|
||||
/*package*/ static Map<String, PropSetter> getNativePropSettersForShadowNodeClass(
|
||||
Class<? extends ReactShadowNode> cls) {
|
||||
if (cls == null) {
|
||||
if (cls == ReactShadowNode.class) {
|
||||
return EMPTY_PROPS_MAP;
|
||||
}
|
||||
Map<String, PropSetter> props = CLASS_PROPS_CACHE.get(cls);
|
||||
|
|
|
@ -9,21 +9,23 @@
|
|||
|
||||
package com.facebook.react.views.art;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder;
|
||||
import com.facebook.react.uimanager.ReactShadowNodeImpl;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import javax.annotation.Nullable;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
|
||||
/**
|
||||
* Base class for ARTView virtual nodes: {@link ARTGroupShadowNode}, {@link ARTShapeShadowNode} and
|
||||
* indirectly for {@link ARTTextShadowNode}.
|
||||
*/
|
||||
public abstract class ARTVirtualNode extends ReactShadowNodeImpl {
|
||||
public abstract class ARTVirtualNode extends ReactShadowNode {
|
||||
|
||||
protected static final float MIN_OPACITY_FOR_DRAW = 0.01f;
|
||||
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
package com.facebook.react.views.modal;
|
||||
|
||||
import android.graphics.Point;
|
||||
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.uimanager.ReactShadowNodeImpl;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
|
||||
/**
|
||||
* We implement the Modal by using an Android Dialog. That will fill the entire window of the
|
||||
|
@ -25,10 +26,10 @@ class ModalHostShadowNode extends LayoutShadowNode {
|
|||
|
||||
/**
|
||||
* We need to set the styleWidth and styleHeight of the one child (represented by the <View/>
|
||||
* within the <RCTModalHostView/> in Modal.js. This needs to fill the entire window.
|
||||
* within the <RCTModalHostView/> in Modal.js. This needs to fill the entire window.
|
||||
*/
|
||||
@Override
|
||||
public void addChildAt(ReactShadowNodeImpl child, int i) {
|
||||
public void addChildAt(ReactShadowNode child, int i) {
|
||||
super.addChildAt(child, i);
|
||||
Point modalSize = ModalHostHelper.getModalHostSize(getThemedContext());
|
||||
child.setStyleWidth(modalSize.x);
|
||||
|
|
|
@ -9,15 +9,16 @@ package com.facebook.react.views.text;
|
|||
|
||||
import com.facebook.react.common.annotations.VisibleForTesting;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
import com.facebook.react.uimanager.ReactShadowNodeImpl;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* {@link ReactShadowNode} class for pure raw text node (aka {@code textContent} in terms of DOM).
|
||||
* Raw text node can only have simple string value without any attributes, properties or state.
|
||||
* {@link ReactShadowNode} class for pure raw text node
|
||||
* (aka {@code textContent} in terms of DOM).
|
||||
* Raw text node can only have simple string value without any attributes,
|
||||
* properties or state.
|
||||
*/
|
||||
public class ReactRawTextShadowNode extends ReactShadowNodeImpl {
|
||||
public class ReactRawTextShadowNode extends ReactShadowNode {
|
||||
|
||||
@VisibleForTesting public static final String PROP_TEXT = "text";
|
||||
|
||||
|
|
|
@ -9,25 +9,27 @@
|
|||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.JavaOnlyMap;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import com.facebook.react.bridge.JavaOnlyMap;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
import javax.annotation.Nullable;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
/**
|
||||
* Test {@link ReactProp} annotation for {@link ReactShadowNode}. More comprahensive test of this
|
||||
* annotation can be found in {@link ReactPropAnnotationSetterTest} where we test all possible types
|
||||
|
@ -59,7 +61,7 @@ public class ReactPropForShadowNodeSetterTest {
|
|||
return new ReactStylesDiffMap(JavaOnlyMap.of(keysAndValues));
|
||||
}
|
||||
|
||||
private class ShadowViewUnderTest extends ReactShadowNodeImpl {
|
||||
private class ShadowViewUnderTest extends ReactShadowNode {
|
||||
|
||||
private ViewManagerUpdatesReceiver mViewManagerUpdatesReceiver;
|
||||
|
||||
|
|
|
@ -9,12 +9,15 @@
|
|||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
import java.util.Map;
|
||||
import org.junit.Rule;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
|
@ -66,61 +69,55 @@ public class ReactPropForShadowNodeSpecTest {
|
|||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testMethodWithWrongNumberOfParams() {
|
||||
new BaseViewManager(
|
||||
new ReactShadowNodeImpl() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithIncorrectNumberOfArgs(boolean value, int anotherValue) {}
|
||||
}.getClass())
|
||||
.getNativeProps();
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithIncorrectNumberOfArgs(boolean value, int anotherValue) {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testMethodWithTooFewParams() {
|
||||
new BaseViewManager(
|
||||
new ReactShadowNodeImpl() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithNoArgs() {}
|
||||
}.getClass())
|
||||
.getNativeProps();
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithNoArgs() {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testUnsupportedValueType() {
|
||||
new BaseViewManager(
|
||||
new ReactShadowNodeImpl() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithMap(Map value) {}
|
||||
}.getClass())
|
||||
.getNativeProps();
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithMap(Map value) {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testGroupInvalidNumberOfParams() {
|
||||
new BaseViewManager(
|
||||
new ReactShadowNodeImpl() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithTooManyParams(int index, float value, boolean bool) {}
|
||||
}.getClass())
|
||||
.getNativeProps();
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithTooManyParams(int index, float value, boolean bool) {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testGroupTooFewParams() {
|
||||
new BaseViewManager(
|
||||
new ReactShadowNodeImpl() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithTooManyParams(int index) {}
|
||||
}.getClass())
|
||||
.getNativeProps();
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithTooManyParams(int index) {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testGroupNoIndexParam() {
|
||||
new BaseViewManager(
|
||||
new ReactShadowNodeImpl() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithTooManyParams(float value, boolean bool) {}
|
||||
}.getClass())
|
||||
.getNativeProps();
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithTooManyParams(float value, boolean bool) {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue