Support string color values in Animated.Color
Summary: In addition to rgba values, allow creating Animated.Color with a string color. Followup changes will include support for platform colors and native driver. Changelog: [General][Added] - Support string color values in Animated.Color Reviewed By: javache Differential Revision: D33810717 fbshipit-source-id: 208bc2675b6153a515fbf2122da15a065c473e73
This commit is contained in:
Родитель
34dcbfb8d9
Коммит
d3a0c4129d
|
@ -974,6 +974,37 @@ describe('Animated tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Animated Colors', () => {
|
describe('Animated Colors', () => {
|
||||||
|
it('should normalize colors', () => {
|
||||||
|
let color = new Animated.Color();
|
||||||
|
expect(color.__getValue()).toEqual('rgba(0, 0, 0, 1)');
|
||||||
|
|
||||||
|
color = new Animated.Color({r: 11, g: 22, b: 33, a: 1.0});
|
||||||
|
expect(color.__getValue()).toEqual('rgba(11, 22, 33, 1)');
|
||||||
|
|
||||||
|
color = new Animated.Color('rgba(255, 0, 0, 1.0)');
|
||||||
|
expect(color.__getValue()).toEqual('rgba(255, 0, 0, 1)');
|
||||||
|
|
||||||
|
color = new Animated.Color('#ff0000ff');
|
||||||
|
expect(color.__getValue()).toEqual('rgba(255, 0, 0, 1)');
|
||||||
|
|
||||||
|
color = new Animated.Color('red');
|
||||||
|
expect(color.__getValue()).toEqual('rgba(255, 0, 0, 1)');
|
||||||
|
|
||||||
|
color = new Animated.Color({
|
||||||
|
r: new Animated.Value(255),
|
||||||
|
g: new Animated.Value(0),
|
||||||
|
b: new Animated.Value(0),
|
||||||
|
a: new Animated.Value(1.0),
|
||||||
|
});
|
||||||
|
expect(color.__getValue()).toEqual('rgba(255, 0, 0, 1)');
|
||||||
|
|
||||||
|
color = new Animated.Color('unknown');
|
||||||
|
expect(color.__getValue()).toEqual('rgba(0, 0, 0, 1)');
|
||||||
|
|
||||||
|
color = new Animated.Color({key: 'value'});
|
||||||
|
expect(color.__getValue()).toEqual('rgba(0, 0, 0, 1)');
|
||||||
|
});
|
||||||
|
|
||||||
it('should animate colors', () => {
|
it('should animate colors', () => {
|
||||||
const color = new Animated.Color({r: 255, g: 0, b: 0, a: 1.0});
|
const color = new Animated.Color({r: 255, g: 0, b: 0, a: 1.0});
|
||||||
const callback = jest.fn();
|
const callback = jest.fn();
|
||||||
|
|
|
@ -12,12 +12,79 @@
|
||||||
|
|
||||||
import AnimatedValue from './AnimatedValue';
|
import AnimatedValue from './AnimatedValue';
|
||||||
import AnimatedWithChildren from './AnimatedWithChildren';
|
import AnimatedWithChildren from './AnimatedWithChildren';
|
||||||
import invariant from 'invariant';
|
import normalizeColor from '../../StyleSheet/normalizeColor';
|
||||||
|
import {processColorObject} from '../../StyleSheet/PlatformColorValueTypes';
|
||||||
|
|
||||||
|
import type {ColorValue} from '../../StyleSheet/StyleSheet';
|
||||||
|
import type {NativeColorValue} from '../../StyleSheet/PlatformColorValueTypes';
|
||||||
|
|
||||||
type ColorListenerCallback = (value: string) => mixed;
|
type ColorListenerCallback = (value: string) => mixed;
|
||||||
|
type RgbaValue = {
|
||||||
|
+r: number,
|
||||||
|
+g: number,
|
||||||
|
+b: number,
|
||||||
|
+a: number,
|
||||||
|
...
|
||||||
|
};
|
||||||
|
type RgbaAnimatedValue = {
|
||||||
|
+r: AnimatedValue,
|
||||||
|
+g: AnimatedValue,
|
||||||
|
+b: AnimatedValue,
|
||||||
|
+a: AnimatedValue,
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultColor: RgbaValue = {r: 0, g: 0, b: 0, a: 1.0};
|
||||||
let _uniqueId = 1;
|
let _uniqueId = 1;
|
||||||
|
|
||||||
|
/* eslint no-bitwise: 0 */
|
||||||
|
function processColor(color?: ?ColorValue): ?(RgbaValue | NativeColorValue) {
|
||||||
|
if (color === undefined || color === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let normalizedColor = normalizeColor(color);
|
||||||
|
if (normalizedColor === undefined || normalizedColor === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof normalizedColor === 'object') {
|
||||||
|
const processedColorObj = processColorObject(normalizedColor);
|
||||||
|
if (processedColorObj != null) {
|
||||||
|
return processedColorObj;
|
||||||
|
}
|
||||||
|
} else if (typeof normalizedColor === 'number') {
|
||||||
|
const r = (normalizedColor & 0xff000000) >>> 24;
|
||||||
|
const g = (normalizedColor & 0x00ff0000) >>> 16;
|
||||||
|
const b = (normalizedColor & 0x0000ff00) >>> 8;
|
||||||
|
const a = (normalizedColor & 0x000000ff) / 255;
|
||||||
|
|
||||||
|
return {r, g, b, a};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRgbaValue(value: any): boolean {
|
||||||
|
return (
|
||||||
|
value &&
|
||||||
|
typeof value.r === 'number' &&
|
||||||
|
typeof value.g === 'number' &&
|
||||||
|
typeof value.b === 'number' &&
|
||||||
|
typeof value.a === 'number'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRgbaAnimatedValue(value: any): boolean {
|
||||||
|
return (
|
||||||
|
value &&
|
||||||
|
value.r instanceof AnimatedValue &&
|
||||||
|
value.g instanceof AnimatedValue &&
|
||||||
|
value.b instanceof AnimatedValue &&
|
||||||
|
value.a instanceof AnimatedValue
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default class AnimatedColor extends AnimatedWithChildren {
|
export default class AnimatedColor extends AnimatedWithChildren {
|
||||||
r: AnimatedValue;
|
r: AnimatedValue;
|
||||||
g: AnimatedValue;
|
g: AnimatedValue;
|
||||||
|
@ -34,39 +101,32 @@ export default class AnimatedColor extends AnimatedWithChildren {
|
||||||
...
|
...
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(valueIn?: ?(RgbaValue | RgbaAnimatedValue | ColorValue)) {
|
||||||
valueIn?: ?{
|
|
||||||
+r: number | AnimatedValue,
|
|
||||||
+g: number | AnimatedValue,
|
|
||||||
+b: number | AnimatedValue,
|
|
||||||
+a: number | AnimatedValue,
|
|
||||||
...
|
|
||||||
}, // TODO: support string color and platform color
|
|
||||||
) {
|
|
||||||
super();
|
super();
|
||||||
const value: any = valueIn || {r: 0, g: 0, b: 0, a: 1}; // @flowfixme: shouldn't need `: any`
|
let value: RgbaValue | RgbaAnimatedValue | ColorValue =
|
||||||
if (
|
valueIn || defaultColor;
|
||||||
typeof value.r === 'number' &&
|
|
||||||
typeof value.g === 'number' &&
|
if (isRgbaAnimatedValue(value)) {
|
||||||
typeof value.b === 'number' &&
|
// $FlowIgnore[incompatible-cast] - Type is verified above
|
||||||
typeof value.a === 'number'
|
const rgbaAnimatedValue: RgbaAnimatedValue = (value: RgbaAnimatedValue);
|
||||||
) {
|
this.r = rgbaAnimatedValue.r;
|
||||||
this.r = new AnimatedValue(value.r);
|
this.g = rgbaAnimatedValue.g;
|
||||||
this.g = new AnimatedValue(value.g);
|
this.b = rgbaAnimatedValue.b;
|
||||||
this.b = new AnimatedValue(value.b);
|
this.a = rgbaAnimatedValue.a;
|
||||||
this.a = new AnimatedValue(value.a);
|
|
||||||
} else {
|
} else {
|
||||||
invariant(
|
// Handle potential parsable string color or platform color object
|
||||||
value.r instanceof AnimatedValue &&
|
if (!isRgbaValue(value)) {
|
||||||
value.g instanceof AnimatedValue &&
|
// $FlowIgnore[incompatible-cast] - Type is verified via conditionals
|
||||||
value.b instanceof AnimatedValue &&
|
value = processColor((value: ColorValue)) || {r: 0, g: 0, b: 0, a: 1.0};
|
||||||
value.a instanceof AnimatedValue,
|
// TODO: support platform color
|
||||||
'AnimatedColor must be initialized with an object of numbers or AnimatedValues.',
|
}
|
||||||
);
|
|
||||||
this.r = value.r;
|
// $FlowIgnore[incompatible-cast] - Type is verified via conditionals
|
||||||
this.g = value.g;
|
const rgbaValue: RgbaValue = (value: RgbaValue);
|
||||||
this.b = value.b;
|
this.r = new AnimatedValue(rgbaValue.r);
|
||||||
this.a = value.a;
|
this.g = new AnimatedValue(rgbaValue.g);
|
||||||
|
this.b = new AnimatedValue(rgbaValue.b);
|
||||||
|
this.a = new AnimatedValue(rgbaValue.a);
|
||||||
}
|
}
|
||||||
this._listeners = {};
|
this._listeners = {};
|
||||||
}
|
}
|
||||||
|
@ -75,7 +135,7 @@ export default class AnimatedColor extends AnimatedWithChildren {
|
||||||
* Directly set the value. This will stop any animations running on the value
|
* Directly set the value. This will stop any animations running on the value
|
||||||
* and update all the bound properties.
|
* and update all the bound properties.
|
||||||
*/
|
*/
|
||||||
setValue(value: {r: number, g: number, b: number, a: number, ...}) {
|
setValue(value: {r: number, g: number, b: number, a: number, ...}): void {
|
||||||
this.r.setValue(value.r);
|
this.r.setValue(value.r);
|
||||||
this.g.setValue(value.g);
|
this.g.setValue(value.g);
|
||||||
this.b.setValue(value.b);
|
this.b.setValue(value.b);
|
||||||
|
@ -87,7 +147,7 @@ export default class AnimatedColor extends AnimatedWithChildren {
|
||||||
* via `setValue`, an animation, or `Animated.event`. Useful for compensating
|
* via `setValue`, an animation, or `Animated.event`. Useful for compensating
|
||||||
* things like the start of a pan gesture.
|
* things like the start of a pan gesture.
|
||||||
*/
|
*/
|
||||||
setOffset(offset: {r: number, g: number, b: number, a: number, ...}) {
|
setOffset(offset: {r: number, g: number, b: number, a: number, ...}): void {
|
||||||
this.r.setOffset(offset.r);
|
this.r.setOffset(offset.r);
|
||||||
this.g.setOffset(offset.g);
|
this.g.setOffset(offset.g);
|
||||||
this.b.setOffset(offset.b);
|
this.b.setOffset(offset.b);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче