diff --git a/Libraries/Animated/nodes/AnimatedColor.js b/Libraries/Animated/nodes/AnimatedColor.js index 4a5cdc5d748..356982ef28d 100644 --- a/Libraries/Animated/nodes/AnimatedColor.js +++ b/Libraries/Animated/nodes/AnimatedColor.js @@ -91,6 +91,7 @@ export default class AnimatedColor extends AnimatedWithChildren { g: AnimatedValue; b: AnimatedValue; a: AnimatedValue; + nativeColor: Object; _listeners: { [key: string]: { r: string, @@ -105,8 +106,16 @@ export default class AnimatedColor extends AnimatedWithChildren { constructor(valueIn?: ?(RgbaValue | RgbaAnimatedValue | ColorValue)) { super(); let value: RgbaValue | RgbaAnimatedValue | ColorValue = - valueIn || defaultColor; + valueIn ?? defaultColor; + this.setValue(value); + this._listeners = {}; + } + /** + * Directly set the value. This will stop any animations running on the value + * and update all the bound properties. + */ + setValue(value: RgbaValue | RgbaAnimatedValue | ColorValue): void { if (isRgbaAnimatedValue(value)) { // $FlowIgnore[incompatible-cast] - Type is verified above const rgbaAnimatedValue: RgbaAnimatedValue = (value: RgbaAnimatedValue); @@ -118,29 +127,50 @@ export default class AnimatedColor extends AnimatedWithChildren { // Handle potential parsable string color or platform color object if (!isRgbaValue(value)) { // $FlowIgnore[incompatible-cast] - Type is verified via conditionals - value = processColor((value: ColorValue)) || {r: 0, g: 0, b: 0, a: 1.0}; - // TODO: support platform color + value = processColor((value: ColorValue)) ?? defaultColor; } - // $FlowIgnore[incompatible-cast] - Type is verified via conditionals - const rgbaValue: RgbaValue = (value: RgbaValue); - this.r = new AnimatedValue(rgbaValue.r); - this.g = new AnimatedValue(rgbaValue.g); - this.b = new AnimatedValue(rgbaValue.b); - this.a = new AnimatedValue(rgbaValue.a); - } - this._listeners = {}; - } + if (!isRgbaValue(value)) { + // We are using a platform color + this.nativeColor = value; + value = defaultColor; + } - /** - * Directly set the value. This will stop any animations running on the value - * and update all the bound properties. - */ - setValue(value: {r: number, g: number, b: number, a: number, ...}): void { - this.r.setValue(value.r); - this.g.setValue(value.g); - this.b.setValue(value.b); - this.a.setValue(value.a); + if (isRgbaValue(value)) { + // $FlowIgnore[incompatible-cast] - Type is verified via conditionals + const rgbaValue: RgbaValue = (value: RgbaValue); + + if (this.r) { + this.r.setValue(rgbaValue.r); + } else { + this.r = new AnimatedValue(rgbaValue.r); + } + + if (this.g) { + this.g.setValue(rgbaValue.g); + } else { + this.g = new AnimatedValue(rgbaValue.g); + } + + if (this.b) { + this.b.setValue(rgbaValue.b); + } else { + this.b = new AnimatedValue(rgbaValue.b); + } + + if (this.a) { + this.a.setValue(rgbaValue.a); + } else { + this.a = new AnimatedValue(rgbaValue.a); + } + } + + if (this.nativeColor) { + this.__makeNative(); + // TODO (T111170195): In order to support setValue() with a platform color, update the + // native AnimatedNode (if it exists) with a new config. + } + } } /** @@ -148,7 +178,7 @@ export default class AnimatedColor extends AnimatedWithChildren { * via `setValue`, an animation, or `Animated.event`. Useful for compensating * things like the start of a pan gesture. */ - setOffset(offset: {r: number, g: number, b: number, a: number, ...}): void { + setOffset(offset: RgbaValue): void { this.r.setOffset(offset.r); this.g.setOffset(offset.g); this.b.setOffset(offset.b); @@ -280,6 +310,7 @@ export default class AnimatedColor extends AnimatedWithChildren { g: this.g.__getNativeTag(), b: this.b.__getNativeTag(), a: this.a.__getNativeTag(), + nativeColor: this.nativeColor, }; } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/ColorAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/ColorAnimatedNode.java index 0624a866ab9..68949f82f77 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/ColorAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/ColorAnimatedNode.java @@ -7,6 +7,9 @@ package com.facebook.react.animated; +import android.graphics.Color; +import com.facebook.react.bridge.ColorPropConverter; +import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.views.view.ColorUtil; @@ -14,6 +17,7 @@ import com.facebook.react.views.view.ColorUtil; /*package*/ class ColorAnimatedNode extends AnimatedNode { private final NativeAnimatedNodesManager mNativeAnimatedNodesManager; + private final ReactApplicationContext mReactApplicationContext; private final int mRNodeId; private final int mGNodeId; private final int mBNodeId; @@ -21,14 +25,16 @@ import com.facebook.react.views.view.ColorUtil; private int mColor; public ColorAnimatedNode( - ReadableMap config, NativeAnimatedNodesManager nativeAnimatedNodesManager) { + ReadableMap config, + NativeAnimatedNodesManager nativeAnimatedNodesManager, + ReactApplicationContext reactApplicationContext) { mNativeAnimatedNodesManager = nativeAnimatedNodesManager; + mReactApplicationContext = reactApplicationContext; mRNodeId = config.getInt("r"); mGNodeId = config.getInt("g"); mBNodeId = config.getInt("b"); mANodeId = config.getInt("a"); - - // TODO (T110930421): Support platform color + setNativeColor(config.getMap("nativeColor")); } public int getColor() { @@ -37,15 +43,15 @@ import com.facebook.react.views.view.ColorUtil; @Override public void update() { - AnimatedNode rNode = mNativeAnimatedNodesManager.getNodeById(mRNodeId); - AnimatedNode gNode = mNativeAnimatedNodesManager.getNodeById(mGNodeId); - AnimatedNode bNode = mNativeAnimatedNodesManager.getNodeById(mBNodeId); - AnimatedNode aNode = mNativeAnimatedNodesManager.getNodeById(mANodeId); + ValueAnimatedNode rNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mRNodeId); + ValueAnimatedNode gNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mGNodeId); + ValueAnimatedNode bNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mBNodeId); + ValueAnimatedNode aNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mANodeId); - double r = ((ValueAnimatedNode) rNode).getValue(); - double g = ((ValueAnimatedNode) gNode).getValue(); - double b = ((ValueAnimatedNode) bNode).getValue(); - double a = ((ValueAnimatedNode) aNode).getValue(); + double r = rNode.getValue(); + double g = gNode.getValue(); + double b = bNode.getValue(); + double a = aNode.getValue(); mColor = ColorUtil.normalize(r, g, b, a); } @@ -63,4 +69,25 @@ import com.facebook.react.views.view.ColorUtil; + " a: " + mANodeId; } + + private void setNativeColor(ReadableMap nativeColor) { + if (nativeColor == null) { + return; + } + + int color = + ColorPropConverter.getColor(nativeColor, mReactApplicationContext.getCurrentActivity()); + + ValueAnimatedNode rNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mRNodeId); + ValueAnimatedNode gNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mGNodeId); + ValueAnimatedNode bNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mBNodeId); + ValueAnimatedNode aNode = (ValueAnimatedNode) mNativeAnimatedNodesManager.getNodeById(mANodeId); + + rNode.mValue = Color.red(color); + gNode.mValue = Color.green(color); + bNode.mValue = Color.blue(color); + aNode.mValue = Color.alpha(color) / 255.0; + + update(); + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java index 10252abfa11..208272eadc1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java @@ -130,7 +130,7 @@ import java.util.Queue; } else if ("value".equals(type)) { node = new ValueAnimatedNode(config); } else if ("color".equals(type)) { - node = new ColorAnimatedNode(config, this); + node = new ColorAnimatedNode(config, this, mReactApplicationContext); } else if ("props".equals(type)) { node = new PropsAnimatedNode(config, this); } else if ("interpolation".equals(type)) {