mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-04 17:39:48 +08:00
Reviewed By: AaaChiuuu Differential Revision: D5871546 fbshipit-source-id: 7c338fe3b747a79377a54867c789028d221b3dd5
684 lines
16 KiB
Java
684 lines
16 KiB
Java
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
|
|
package com.facebook.react.uimanager;
|
|
|
|
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;
|
|
import com.facebook.yoga.YogaFlexDirection;
|
|
import com.facebook.yoga.YogaJustify;
|
|
import com.facebook.yoga.YogaOverflow;
|
|
import com.facebook.yoga.YogaPositionType;
|
|
import com.facebook.yoga.YogaUnit;
|
|
import com.facebook.yoga.YogaWrap;
|
|
import javax.annotation.Nullable;
|
|
|
|
/**
|
|
* 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
|
|
* explored, namely using the VirtualText class in JS and setting the correct set of validAttributes
|
|
*/
|
|
public class LayoutShadowNode extends ReactShadowNodeImpl {
|
|
|
|
/**
|
|
* A Mutable version of com.facebook.yoga.YogaValue
|
|
*/
|
|
private static class MutableYogaValue {
|
|
float value;
|
|
YogaUnit unit;
|
|
|
|
void setFromDynamic(Dynamic dynamic) {
|
|
if (dynamic.isNull()) {
|
|
unit = YogaUnit.UNDEFINED;
|
|
value = YogaConstants.UNDEFINED;
|
|
} else if (dynamic.getType() == ReadableType.String) {
|
|
final String s = dynamic.asString();
|
|
if (s.equals("auto")) {
|
|
unit = YogaUnit.AUTO;
|
|
value = YogaConstants.UNDEFINED;
|
|
} else if (s.endsWith("%")) {
|
|
unit = YogaUnit.PERCENT;
|
|
value = Float.parseFloat(s.substring(0, s.length() - 1));
|
|
} else {
|
|
throw new IllegalArgumentException("Unknown value: " + s);
|
|
}
|
|
} else {
|
|
unit = YogaUnit.POINT;
|
|
value = PixelUtil.toPixelFromDIP(dynamic.asDouble());
|
|
}
|
|
}
|
|
}
|
|
|
|
private final MutableYogaValue mTempYogaValue = new MutableYogaValue();
|
|
|
|
@ReactProp(name = ViewProps.WIDTH)
|
|
public void setWidth(Dynamic width) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
mTempYogaValue.setFromDynamic(width);
|
|
switch (mTempYogaValue.unit) {
|
|
case POINT:
|
|
case UNDEFINED:
|
|
setStyleWidth(mTempYogaValue.value);
|
|
break;
|
|
case AUTO:
|
|
setStyleWidthAuto();
|
|
break;
|
|
case PERCENT:
|
|
setStyleWidthPercent(mTempYogaValue.value);
|
|
break;
|
|
}
|
|
|
|
width.recycle();
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.MIN_WIDTH)
|
|
public void setMinWidth(Dynamic minWidth) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
mTempYogaValue.setFromDynamic(minWidth);
|
|
switch (mTempYogaValue.unit) {
|
|
case POINT:
|
|
case UNDEFINED:
|
|
setStyleMinWidth(mTempYogaValue.value);
|
|
break;
|
|
case PERCENT:
|
|
setStyleMinWidthPercent(mTempYogaValue.value);
|
|
break;
|
|
}
|
|
|
|
minWidth.recycle();
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.MAX_WIDTH)
|
|
public void setMaxWidth(Dynamic maxWidth) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
mTempYogaValue.setFromDynamic(maxWidth);
|
|
switch (mTempYogaValue.unit) {
|
|
case POINT:
|
|
case UNDEFINED:
|
|
setStyleMaxWidth(mTempYogaValue.value);
|
|
break;
|
|
case PERCENT:
|
|
setStyleMaxWidthPercent(mTempYogaValue.value);
|
|
break;
|
|
}
|
|
|
|
maxWidth.recycle();
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.HEIGHT)
|
|
public void setHeight(Dynamic height) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
mTempYogaValue.setFromDynamic(height);
|
|
switch (mTempYogaValue.unit) {
|
|
case POINT:
|
|
case UNDEFINED:
|
|
setStyleHeight(mTempYogaValue.value);
|
|
break;
|
|
case AUTO:
|
|
setStyleHeightAuto();
|
|
break;
|
|
case PERCENT:
|
|
setStyleHeightPercent(mTempYogaValue.value);
|
|
break;
|
|
}
|
|
|
|
height.recycle();
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.MIN_HEIGHT)
|
|
public void setMinHeight(Dynamic minHeight) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
mTempYogaValue.setFromDynamic(minHeight);
|
|
switch (mTempYogaValue.unit) {
|
|
case POINT:
|
|
case UNDEFINED:
|
|
setStyleMinHeight(mTempYogaValue.value);
|
|
break;
|
|
case PERCENT:
|
|
setStyleMinHeightPercent(mTempYogaValue.value);
|
|
break;
|
|
}
|
|
|
|
minHeight.recycle();
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.MAX_HEIGHT)
|
|
public void setMaxHeight(Dynamic maxHeight) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
mTempYogaValue.setFromDynamic(maxHeight);
|
|
switch (mTempYogaValue.unit) {
|
|
case POINT:
|
|
case UNDEFINED:
|
|
setStyleMaxHeight(mTempYogaValue.value);
|
|
break;
|
|
case PERCENT:
|
|
setStyleMaxHeightPercent(mTempYogaValue.value);
|
|
break;
|
|
}
|
|
|
|
maxHeight.recycle();
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.FLEX, defaultFloat = 0f)
|
|
public void setFlex(float flex) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
super.setFlex(flex);
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.FLEX_GROW, defaultFloat = 0f)
|
|
public void setFlexGrow(float flexGrow) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
super.setFlexGrow(flexGrow);
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.FLEX_SHRINK, defaultFloat = 0f)
|
|
public void setFlexShrink(float flexShrink) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
super.setFlexShrink(flexShrink);
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.FLEX_BASIS)
|
|
public void setFlexBasis(Dynamic flexBasis) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
mTempYogaValue.setFromDynamic(flexBasis);
|
|
switch (mTempYogaValue.unit) {
|
|
case POINT:
|
|
case UNDEFINED:
|
|
setFlexBasis(mTempYogaValue.value);
|
|
break;
|
|
case AUTO:
|
|
setFlexBasisAuto();
|
|
break;
|
|
case PERCENT:
|
|
setFlexBasisPercent(mTempYogaValue.value);
|
|
break;
|
|
}
|
|
|
|
flexBasis.recycle();
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.ASPECT_RATIO, defaultFloat = YogaConstants.UNDEFINED)
|
|
public void setAspectRatio(float aspectRatio) {
|
|
setStyleAspectRatio(aspectRatio);
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.FLEX_DIRECTION)
|
|
public void setFlexDirection(@Nullable String flexDirection) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
if (flexDirection == null) {
|
|
setFlexDirection(YogaFlexDirection.COLUMN);
|
|
return;
|
|
}
|
|
|
|
switch (flexDirection) {
|
|
case "column": {
|
|
setFlexDirection(YogaFlexDirection.COLUMN);
|
|
break;
|
|
}
|
|
case "column-reverse": {
|
|
setFlexDirection(YogaFlexDirection.COLUMN_REVERSE);
|
|
break;
|
|
}
|
|
case "row": {
|
|
setFlexDirection(YogaFlexDirection.ROW);
|
|
break;
|
|
}
|
|
case "row-reverse": {
|
|
setFlexDirection(YogaFlexDirection.ROW_REVERSE);
|
|
break;
|
|
}
|
|
default: {
|
|
throw new JSApplicationIllegalArgumentException(
|
|
"invalid value for flexDirection: " + flexDirection);
|
|
}
|
|
}
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.FLEX_WRAP)
|
|
public void setFlexWrap(@Nullable String flexWrap) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
if (flexWrap == null) {
|
|
setFlexWrap(YogaWrap.NO_WRAP);
|
|
return;
|
|
}
|
|
|
|
switch (flexWrap) {
|
|
case "nowrap": {
|
|
setFlexWrap(YogaWrap.NO_WRAP);
|
|
break;
|
|
}
|
|
case "wrap": {
|
|
setFlexWrap(YogaWrap.WRAP);
|
|
break;
|
|
}
|
|
default: {
|
|
throw new JSApplicationIllegalArgumentException(
|
|
"invalid value for flexWrap: " + flexWrap);
|
|
}
|
|
}
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.ALIGN_SELF)
|
|
public void setAlignSelf(@Nullable String alignSelf) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
if (alignSelf == null) {
|
|
setAlignSelf(YogaAlign.AUTO);
|
|
return;
|
|
}
|
|
|
|
switch (alignSelf) {
|
|
case "auto": {
|
|
setAlignSelf(YogaAlign.AUTO);
|
|
return;
|
|
}
|
|
case "flex-start": {
|
|
setAlignSelf(YogaAlign.FLEX_START);
|
|
return;
|
|
}
|
|
case "center": {
|
|
setAlignSelf(YogaAlign.CENTER);
|
|
return;
|
|
}
|
|
case "flex-end": {
|
|
setAlignSelf(YogaAlign.FLEX_END);
|
|
return;
|
|
}
|
|
case "stretch": {
|
|
setAlignSelf(YogaAlign.STRETCH);
|
|
return;
|
|
}
|
|
case "baseline": {
|
|
setAlignSelf(YogaAlign.BASELINE);
|
|
return;
|
|
}
|
|
case "space-between": {
|
|
setAlignSelf(YogaAlign.SPACE_BETWEEN);
|
|
return;
|
|
}
|
|
case "space-around": {
|
|
setAlignSelf(YogaAlign.SPACE_AROUND);
|
|
return;
|
|
}
|
|
default: {
|
|
throw new JSApplicationIllegalArgumentException(
|
|
"invalid value for alignSelf: " + alignSelf);
|
|
}
|
|
}
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.ALIGN_ITEMS)
|
|
public void setAlignItems(@Nullable String alignItems) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
if (alignItems == null) {
|
|
setAlignItems(YogaAlign.STRETCH);
|
|
return;
|
|
}
|
|
|
|
switch (alignItems) {
|
|
case "auto": {
|
|
setAlignItems(YogaAlign.AUTO);
|
|
return;
|
|
}
|
|
case "flex-start": {
|
|
setAlignItems(YogaAlign.FLEX_START);
|
|
return;
|
|
}
|
|
case "center": {
|
|
setAlignItems(YogaAlign.CENTER);
|
|
return;
|
|
}
|
|
case "flex-end": {
|
|
setAlignItems(YogaAlign.FLEX_END);
|
|
return;
|
|
}
|
|
case "stretch": {
|
|
setAlignItems(YogaAlign.STRETCH);
|
|
return;
|
|
}
|
|
case "baseline": {
|
|
setAlignItems(YogaAlign.BASELINE);
|
|
return;
|
|
}
|
|
case "space-between": {
|
|
setAlignItems(YogaAlign.SPACE_BETWEEN);
|
|
return;
|
|
}
|
|
case "space-around": {
|
|
setAlignItems(YogaAlign.SPACE_AROUND);
|
|
return;
|
|
}
|
|
default: {
|
|
throw new JSApplicationIllegalArgumentException(
|
|
"invalid value for alignItems: " + alignItems);
|
|
}
|
|
}
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.ALIGN_CONTENT)
|
|
public void setAlignContent(@Nullable String alignContent) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
if (alignContent == null) {
|
|
setAlignContent(YogaAlign.FLEX_START);
|
|
return;
|
|
}
|
|
|
|
switch (alignContent) {
|
|
case "auto": {
|
|
setAlignContent(YogaAlign.AUTO);
|
|
return;
|
|
}
|
|
case "flex-start": {
|
|
setAlignContent(YogaAlign.FLEX_START);
|
|
return;
|
|
}
|
|
case "center": {
|
|
setAlignContent(YogaAlign.CENTER);
|
|
return;
|
|
}
|
|
case "flex-end": {
|
|
setAlignContent(YogaAlign.FLEX_END);
|
|
return;
|
|
}
|
|
case "stretch": {
|
|
setAlignContent(YogaAlign.STRETCH);
|
|
return;
|
|
}
|
|
case "baseline": {
|
|
setAlignContent(YogaAlign.BASELINE);
|
|
return;
|
|
}
|
|
case "space-between": {
|
|
setAlignContent(YogaAlign.SPACE_BETWEEN);
|
|
return;
|
|
}
|
|
case "space-around": {
|
|
setAlignContent(YogaAlign.SPACE_AROUND);
|
|
return;
|
|
}
|
|
default: {
|
|
throw new JSApplicationIllegalArgumentException(
|
|
"invalid value for alignContent: " + alignContent);
|
|
}
|
|
}
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.JUSTIFY_CONTENT)
|
|
public void setJustifyContent(@Nullable String justifyContent) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
if (justifyContent == null) {
|
|
setJustifyContent(YogaJustify.FLEX_START);
|
|
return;
|
|
}
|
|
|
|
switch (justifyContent) {
|
|
case "flex-start": {
|
|
setJustifyContent(YogaJustify.FLEX_START);
|
|
break;
|
|
}
|
|
case "center": {
|
|
setJustifyContent(YogaJustify.CENTER);
|
|
break;
|
|
}
|
|
case "flex-end": {
|
|
setJustifyContent(YogaJustify.FLEX_END);
|
|
break;
|
|
}
|
|
case "space-between": {
|
|
setJustifyContent(YogaJustify.SPACE_BETWEEN);
|
|
break;
|
|
}
|
|
case "space-around": {
|
|
setJustifyContent(YogaJustify.SPACE_AROUND);
|
|
break;
|
|
}
|
|
default: {
|
|
throw new JSApplicationIllegalArgumentException(
|
|
"invalid value for justifyContent: " + justifyContent);
|
|
}
|
|
}
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.OVERFLOW)
|
|
public void setOverflow(@Nullable String overflow) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
if (overflow == null) {
|
|
setOverflow(YogaOverflow.VISIBLE);
|
|
return;
|
|
}
|
|
|
|
switch (overflow) {
|
|
case "visible": {
|
|
setOverflow(YogaOverflow.VISIBLE);
|
|
break;
|
|
}
|
|
case "hidden": {
|
|
setOverflow(YogaOverflow.HIDDEN);
|
|
break;
|
|
}
|
|
case "scroll": {
|
|
setOverflow(YogaOverflow.SCROLL);
|
|
break;
|
|
}
|
|
default: {
|
|
throw new JSApplicationIllegalArgumentException(
|
|
"invalid value for overflow: " + overflow);
|
|
}
|
|
}
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.DISPLAY)
|
|
public void setDisplay(@Nullable String display) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
if (display == null) {
|
|
setDisplay(YogaDisplay.FLEX);
|
|
return;
|
|
}
|
|
|
|
switch (display) {
|
|
case "flex": {
|
|
setDisplay(YogaDisplay.FLEX);
|
|
break;
|
|
}
|
|
case "none": {
|
|
setDisplay(YogaDisplay.NONE);
|
|
break;
|
|
}
|
|
default: {
|
|
throw new JSApplicationIllegalArgumentException(
|
|
"invalid value for display: " + display);
|
|
}
|
|
}
|
|
}
|
|
|
|
@ReactPropGroup(names = {
|
|
ViewProps.MARGIN,
|
|
ViewProps.MARGIN_VERTICAL,
|
|
ViewProps.MARGIN_HORIZONTAL,
|
|
ViewProps.MARGIN_LEFT,
|
|
ViewProps.MARGIN_RIGHT,
|
|
ViewProps.MARGIN_TOP,
|
|
ViewProps.MARGIN_BOTTOM,
|
|
})
|
|
public void setMargins(int index, Dynamic margin) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
mTempYogaValue.setFromDynamic(margin);
|
|
switch (mTempYogaValue.unit) {
|
|
case POINT:
|
|
case UNDEFINED:
|
|
setMargin(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value);
|
|
break;
|
|
case AUTO:
|
|
setMarginAuto(ViewProps.PADDING_MARGIN_SPACING_TYPES[index]);
|
|
break;
|
|
case PERCENT:
|
|
setMarginPercent(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value);
|
|
break;
|
|
}
|
|
|
|
margin.recycle();
|
|
}
|
|
|
|
@ReactPropGroup(names = {
|
|
ViewProps.PADDING,
|
|
ViewProps.PADDING_VERTICAL,
|
|
ViewProps.PADDING_HORIZONTAL,
|
|
ViewProps.PADDING_LEFT,
|
|
ViewProps.PADDING_RIGHT,
|
|
ViewProps.PADDING_TOP,
|
|
ViewProps.PADDING_BOTTOM,
|
|
})
|
|
public void setPaddings(int index, Dynamic padding) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
mTempYogaValue.setFromDynamic(padding);
|
|
switch (mTempYogaValue.unit) {
|
|
case POINT:
|
|
case UNDEFINED:
|
|
setPadding(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value);
|
|
break;
|
|
case PERCENT:
|
|
setPaddingPercent(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value);
|
|
break;
|
|
}
|
|
|
|
padding.recycle();
|
|
}
|
|
|
|
@ReactPropGroup(names = {
|
|
ViewProps.BORDER_WIDTH,
|
|
ViewProps.BORDER_LEFT_WIDTH,
|
|
ViewProps.BORDER_RIGHT_WIDTH,
|
|
ViewProps.BORDER_TOP_WIDTH,
|
|
ViewProps.BORDER_BOTTOM_WIDTH,
|
|
}, defaultFloat = YogaConstants.UNDEFINED)
|
|
public void setBorderWidths(int index, float borderWidth) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
setBorder(ViewProps.BORDER_SPACING_TYPES[index], PixelUtil.toPixelFromDIP(borderWidth));
|
|
}
|
|
|
|
@ReactPropGroup(names = {
|
|
ViewProps.LEFT,
|
|
ViewProps.RIGHT,
|
|
ViewProps.TOP,
|
|
ViewProps.BOTTOM,
|
|
})
|
|
public void setPositionValues(int index, Dynamic position) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
mTempYogaValue.setFromDynamic(position);
|
|
switch (mTempYogaValue.unit) {
|
|
case POINT:
|
|
case UNDEFINED:
|
|
setPosition(ViewProps.POSITION_SPACING_TYPES[index], mTempYogaValue.value);
|
|
break;
|
|
case PERCENT:
|
|
setPositionPercent(ViewProps.POSITION_SPACING_TYPES[index], mTempYogaValue.value);
|
|
break;
|
|
}
|
|
|
|
position.recycle();
|
|
}
|
|
|
|
@ReactProp(name = ViewProps.POSITION)
|
|
public void setPosition(@Nullable String position) {
|
|
if (isVirtual()) {
|
|
return;
|
|
}
|
|
|
|
if (position == null) {
|
|
setPositionType(YogaPositionType.RELATIVE);
|
|
return;
|
|
}
|
|
|
|
switch (position) {
|
|
case "relative": {
|
|
setPositionType(YogaPositionType.RELATIVE);
|
|
break;
|
|
}
|
|
case "absolute": {
|
|
setPositionType(YogaPositionType.ABSOLUTE);
|
|
break;
|
|
}
|
|
default: {
|
|
throw new JSApplicationIllegalArgumentException(
|
|
"invalid value for position: " + position);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
@ReactProp(name = "onLayout")
|
|
public void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout) {
|
|
super.setShouldNotifyOnLayout(shouldNotifyOnLayout);
|
|
}
|
|
}
|