-
Notifications
You must be signed in to change notification settings - Fork 25k
AnimatedWithChildren support for addListener #12620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
6d3b05d
2cc5d3b
f518dc9
7f3c21d
c7b0128
514496e
bebdf03
a0b8473
f28b941
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -90,6 +90,9 @@ class Animated { | |
| __getNativeConfig(): Object { | ||
| throw new Error('This JS animated node type cannot be used as native animated node'); | ||
| } | ||
| // Called before listeners are triggered. | ||
| // Should update internal value so __getValue returns the most recently received value | ||
| __updateValueFromListener(data: Object): void {} | ||
| toJSON(): any { return this.__getValue(); } | ||
| } | ||
|
|
||
|
|
@@ -144,10 +147,13 @@ class Animation { | |
|
|
||
| class AnimatedWithChildren extends Animated { | ||
| _children: Array<Animated>; | ||
| _listeners: {[key: string]: AnimatedListenerCallback}; | ||
| __nativeAnimatedValueListener: ?any; | ||
|
|
||
| constructor() { | ||
| super(); | ||
| this._children = []; | ||
| this._listeners = {}; | ||
| } | ||
|
|
||
| __makeNative() { | ||
|
|
@@ -157,6 +163,9 @@ class AnimatedWithChildren extends Animated { | |
| child.__makeNative(); | ||
| NativeAnimatedAPI.connectAnimatedNodes(this.__getNativeTag(), child.__getNativeTag()); | ||
| } | ||
| if (Object.keys(this._listeners).length) { | ||
| this._startListeningToNativeValueUpdates(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -190,6 +199,74 @@ class AnimatedWithChildren extends Animated { | |
| __getChildren(): Array<Animated> { | ||
| return this._children; | ||
| } | ||
|
|
||
| addListener(callback: AnimatedListenerCallback): string { | ||
| var id = String(_uniqueId++); | ||
| this._listeners[id] = callback; | ||
| if (this.__isNative) { | ||
| this._startListeningToNativeValueUpdates(); | ||
| } | ||
| return id; | ||
| } | ||
|
|
||
| removeListener(id: string): void { | ||
| delete this._listeners[id]; | ||
| if (this.__isNative && Object.keys(this._listeners).length === 0) { | ||
| this._stopListeningForNativeValueUpdates(); | ||
| } | ||
| } | ||
|
|
||
| removeAllListeners(): void { | ||
| this._listeners = {}; | ||
| if (this.__isNative) { | ||
| this._stopListeningForNativeValueUpdates(); | ||
| } | ||
| } | ||
|
|
||
| _startListeningToNativeValueUpdates(): void { | ||
| if (this.__nativeAnimatedValueListener) { | ||
| return; | ||
| } | ||
|
|
||
| NativeAnimatedAPI.startListeningToAnimatedNodeValue(this.__getNativeTag()); | ||
| this.__nativeAnimatedValueListener = NativeAnimatedHelper.nativeEventEmitter.addListener( | ||
| 'onAnimatedValueUpdate', | ||
| (data) => { | ||
| if (data.tag !== this.__getNativeTag()) { | ||
| return; | ||
| } | ||
|
|
||
| this.__updateValueFromListener(data); | ||
| // Native 'onAnimatedValueUpdate' is triggered on all child nodes, | ||
| // so we don't need event propagation | ||
| this.triggerListeners(false /*eventPropagation*/); | ||
| } | ||
| ); | ||
| } | ||
|
|
||
| /* Typically used internally */ | ||
| triggerListeners(eventPropagation?: bool = true): void { | ||
| for (var key in this._listeners) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. keyword-spacing: Expected space(s) after "if". |
||
| this._listeners[key]({value: this.__getValue()}); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. keyword-spacing: Expected space(s) after "if". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. keyword-spacing: Expected space(s) after "if". |
||
| if (eventPropagation) { | ||
| for (var child of this._children) { | ||
| if (child instanceof AnimatedWithChildren) { | ||
| child.triggerListeners(); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| _stopListeningForNativeValueUpdates() { | ||
| if (!this.__nativeAnimatedValueListener) { | ||
| return; | ||
| } | ||
|
|
||
| this.__nativeAnimatedValueListener.remove(); | ||
| this.__nativeAnimatedValueListener = null; | ||
| NativeAnimatedAPI.stopListeningToAnimatedNodeValue(this.__getNativeTag()); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -683,7 +760,7 @@ class SpringAnimation extends Animation { | |
| } | ||
| } | ||
|
|
||
| type ValueListenerCallback = (state: {value: number}) => void; | ||
| type AnimatedListenerCallback = (state: Object) => void; | ||
|
||
|
|
||
| var _uniqueId = 1; | ||
|
|
||
|
|
@@ -698,15 +775,12 @@ class AnimatedValue extends AnimatedWithChildren { | |
| _offset: number; | ||
| _animation: ?Animation; | ||
| _tracking: ?Animated; | ||
| _listeners: {[key: string]: ValueListenerCallback}; | ||
| __nativeAnimatedValueListener: ?any; | ||
|
|
||
| constructor(value: number) { | ||
| super(); | ||
| this._value = value; | ||
| this._offset = 0; | ||
| this._animation = null; | ||
| this._listeners = {}; | ||
| } | ||
|
|
||
| __detach() { | ||
|
|
@@ -720,10 +794,6 @@ class AnimatedValue extends AnimatedWithChildren { | |
|
|
||
| __makeNative() { | ||
| super.__makeNative(); | ||
|
|
||
| if (Object.keys(this._listeners).length) { | ||
| this._startListeningToNativeValueUpdates(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -779,61 +849,6 @@ class AnimatedValue extends AnimatedWithChildren { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Adds an asynchronous listener to the value so you can observe updates from | ||
| * animations. This is useful because there is no way to | ||
| * synchronously read the value because it might be driven natively. | ||
| */ | ||
| addListener(callback: ValueListenerCallback): string { | ||
| var id = String(_uniqueId++); | ||
| this._listeners[id] = callback; | ||
| if (this.__isNative) { | ||
| this._startListeningToNativeValueUpdates(); | ||
| } | ||
| return id; | ||
| } | ||
|
|
||
| removeListener(id: string): void { | ||
| delete this._listeners[id]; | ||
| if (this.__isNative && Object.keys(this._listeners).length === 0) { | ||
| this._stopListeningForNativeValueUpdates(); | ||
| } | ||
| } | ||
|
|
||
| removeAllListeners(): void { | ||
| this._listeners = {}; | ||
| if (this.__isNative) { | ||
| this._stopListeningForNativeValueUpdates(); | ||
| } | ||
| } | ||
|
|
||
| _startListeningToNativeValueUpdates() { | ||
| if (this.__nativeAnimatedValueListener) { | ||
| return; | ||
| } | ||
|
|
||
| NativeAnimatedAPI.startListeningToAnimatedNodeValue(this.__getNativeTag()); | ||
| this.__nativeAnimatedValueListener = NativeAnimatedHelper.nativeEventEmitter.addListener( | ||
| 'onAnimatedValueUpdate', | ||
| (data) => { | ||
| if (data.tag !== this.__getNativeTag()) { | ||
| return; | ||
| } | ||
| this._updateValue(data.value, false /* flush */); | ||
| } | ||
| ); | ||
| } | ||
|
|
||
| _stopListeningForNativeValueUpdates() { | ||
| if (!this.__nativeAnimatedValueListener) { | ||
| return; | ||
| } | ||
|
|
||
| this.__nativeAnimatedValueListener.remove(); | ||
| this.__nativeAnimatedValueListener = null; | ||
| NativeAnimatedAPI.stopListeningToAnimatedNodeValue(this.__getNativeTag()); | ||
| } | ||
|
|
||
| /** | ||
| * Stops any running animation or tracking. `callback` is invoked with the | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. parameter There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. parameter |
||
| * final value after stopping the animation, which is useful for updating | ||
|
|
@@ -901,14 +916,16 @@ class AnimatedValue extends AnimatedWithChildren { | |
| this._tracking = tracking; | ||
| } | ||
|
|
||
| __updateValueFromListener(data: Object): void { | ||
| this._value = data.value; | ||
| } | ||
|
|
||
| _updateValue(value: number, flush: bool): void { | ||
| this._value = value; | ||
| if (flush) { | ||
| _flush(this); | ||
| } | ||
| for (var key in this._listeners) { | ||
| this._listeners[key]({value: this.__getValue()}); | ||
| } | ||
| this.triggerListeners(); | ||
|
||
| } | ||
|
|
||
| __getNativeConfig(): Object { | ||
|
|
@@ -920,8 +937,6 @@ class AnimatedValue extends AnimatedWithChildren { | |
| } | ||
| } | ||
|
|
||
| type ValueXYListenerCallback = (value: {x: number, y: number}) => void; | ||
|
|
||
| /** | ||
| * 2D Value for driving 2D animations, such as pan gestures. Almost identical | ||
| * API to normal `Animated.Value`, but multiplexed. Contains two regular | ||
|
|
@@ -965,7 +980,7 @@ type ValueXYListenerCallback = (value: {x: number, y: number}) => void; | |
| class AnimatedValueXY extends AnimatedWithChildren { | ||
| x: AnimatedValue; | ||
| y: AnimatedValue; | ||
| _listeners: {[key: string]: {x: string, y: string}}; | ||
| _jointListeners: {[key: string]: {x: string, y: string}}; | ||
|
|
||
| constructor(valueIn?: ?{x: number | AnimatedValue, y: number | AnimatedValue}) { | ||
| super(); | ||
|
|
@@ -983,7 +998,7 @@ class AnimatedValueXY extends AnimatedWithChildren { | |
| this.x = value.x; | ||
| this.y = value.y; | ||
| } | ||
| this._listeners = {}; | ||
| this._jointListeners = {}; | ||
| } | ||
|
|
||
| setValue(value: {x: number, y: number}) { | ||
|
|
@@ -1019,12 +1034,12 @@ class AnimatedValueXY extends AnimatedWithChildren { | |
| callback && callback(this.__getValue()); | ||
| } | ||
|
|
||
| addListener(callback: ValueXYListenerCallback): string { | ||
| addListener(callback: AnimatedListenerCallback): string { | ||
| var id = String(_uniqueId++); | ||
| var jointCallback = ({value: number}) => { | ||
| callback(this.__getValue()); | ||
| }; | ||
| this._listeners[id] = { | ||
| this._jointListeners[id] = { | ||
| x: this.x.addListener(jointCallback), | ||
| y: this.y.addListener(jointCallback), | ||
| }; | ||
|
|
@@ -1034,13 +1049,13 @@ class AnimatedValueXY extends AnimatedWithChildren { | |
| removeListener(id: string): void { | ||
| this.x.removeListener(this._listeners[id].x); | ||
| this.y.removeListener(this._listeners[id].y); | ||
| delete this._listeners[id]; | ||
| delete this._jointListeners[id]; | ||
| } | ||
|
|
||
| removeAllListeners(): void { | ||
| this.x.removeAllListeners(); | ||
| this.y.removeAllListeners(); | ||
| this._listeners = {}; | ||
| this._jointListeners = {}; | ||
| } | ||
|
|
||
| /** | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keyword-spacing: Expected space(s) after "if".