Skip to content

Commit

Permalink
Support platform color with AnimatedColor on Android
Browse files Browse the repository at this point in the history
Summary:
Adds support for platform colors in AnimatedColor.
Passes the processed native color object to the native ColorAnimatedNode via the native config; ColorAnimatedNode then uses ColorPropConverter.getColor to resolve the resource path.

Note: setting a platform color via setValue on an existing AnimatedColor is not supported yet

Changelog:
[Android][Added] - Support platform color with AnimatedColor

Reviewed By: yungsters

Differential Revision: D33922266

fbshipit-source-id: 04d39a5ce0872b31d06ffbd4639d2f2213cf3314
  • Loading branch information
genkikondo authored and facebook-github-bot committed Feb 2, 2022
1 parent 3552ff0 commit cb42049
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 34 deletions.
75 changes: 53 additions & 22 deletions Libraries/Animated/nodes/AnimatedColor.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export default class AnimatedColor extends AnimatedWithChildren {
g: AnimatedValue;
b: AnimatedValue;
a: AnimatedValue;
nativeColor: Object;
_listeners: {
[key: string]: {
r: string,
Expand All @@ -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);
Expand All @@ -118,37 +127,58 @@ 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.
}
}
}

/**
* Sets an offset that is applied on top of whatever value is set, whether
* 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);
Expand Down Expand Up @@ -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,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,34 @@

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;

/** Animated node that represents a color. */
/*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;
private final int mANodeId;
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() {
Expand All @@ -37,15 +43,15 @@ public int getColor() {

@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);
}
Expand All @@ -63,4 +69,25 @@ public String prettyPrint() {
+ " 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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public void createAnimatedNode(int tag, ReadableMap config) {
} 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)) {
Expand Down

0 comments on commit cb42049

Please sign in to comment.