diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js index dc8fcc162..2dc9de93b 100644 --- a/Libraries/Animated/src/AnimatedImplementation.js +++ b/Libraries/Animated/src/AnimatedImplementation.js @@ -14,11 +14,11 @@ var InteractionManager = require('InteractionManager'); var Interpolation = require('Interpolation'); +var NativeAnimatedHelper = require('NativeAnimatedHelper'); var React = require('React'); var Set = require('Set'); var SpringConfig = require('SpringConfig'); var ViewStylePropTypes = require('ViewStylePropTypes'); -var NativeAnimatedHelper = require('NativeAnimatedHelper'); var findNodeHandle = require('react/lib/findNodeHandle'); var flattenStyle = require('flattenStyle'); @@ -32,6 +32,26 @@ type EndCallback = (result: EndResult) => void; var NativeAnimatedAPI = NativeAnimatedHelper.API; +var warnedMissingNativeAnimated = false; + +function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean { + if (config.useNativeDriver && + !NativeAnimatedHelper.isNativeAnimatedAvailable()) { + if (!warnedMissingNativeAnimated) { + console.warn( + 'Animated: `useNativeDriver` is not supported because the native ' + + 'animated module is missing. Falling back to JS-based animation. To ' + + 'resolve this, add `RCTAnimation` module to this app, or remove ' + + '`useNativeDriver`.' + ); + warnedMissingNativeAnimated = true; + } + return false; + } + + return config.useNativeDriver || false; +} + // Note(vjeux): this would be better as an interface but flow doesn't // support them yet class Animated { @@ -251,7 +271,7 @@ class TimingAnimation extends Animation { this._duration = config.duration !== undefined ? config.duration : 500; this._delay = config.delay !== undefined ? config.delay : 0; this.__isInteraction = config.isInteraction !== undefined ? config.isInteraction : true; - this._useNativeDriver = config.useNativeDriver !== undefined ? config.useNativeDriver : false; + this._useNativeDriver = shouldUseNativeDriver(config); } __getNativeAnimationConfig(): any { @@ -360,7 +380,7 @@ class DecayAnimation extends Animation { super(); this._deceleration = config.deceleration !== undefined ? config.deceleration : 0.998; this._velocity = config.velocity; - this._useNativeDriver = config.useNativeDriver !== undefined ? config.useNativeDriver : false; + this._useNativeDriver = shouldUseNativeDriver(config); this.__isInteraction = config.isInteraction !== undefined ? config.isInteraction : true; } @@ -479,7 +499,7 @@ class SpringAnimation extends Animation { this._initialVelocity = config.velocity; this._lastVelocity = withDefault(config.velocity, 0); this._toValue = config.toValue; - this._useNativeDriver = config.useNativeDriver !== undefined ? config.useNativeDriver : false; + this._useNativeDriver = shouldUseNativeDriver(config); this.__isInteraction = config.isInteraction !== undefined ? config.isInteraction : true; var springConfig; @@ -2105,8 +2125,8 @@ var stagger = function( type Mapping = {[key: string]: Mapping} | AnimatedValue; type EventConfig = { - listener?: ?Function; - useNativeDriver?: bool; + listener?: ?Function, + useNativeDriver?: bool, }; class AnimatedEvent { @@ -2120,7 +2140,7 @@ class AnimatedEvent { ) { this._argMapping = argMapping; this._listener = config.listener; - this.__isNative = config.useNativeDriver || false; + this.__isNative = shouldUseNativeDriver(config); if (this.__isNative) { invariant(!this._listener, 'Listener is not supported for native driven events.'); diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/src/NativeAnimatedHelper.js index f9ba740df..67aae660c 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/src/NativeAnimatedHelper.js @@ -19,11 +19,11 @@ const invariant = require('fbjs/lib/invariant'); let __nativeAnimatedNodeTagCount = 1; /* used for animated nodes */ let __nativeAnimationIdCount = 1; /* used for started animations */ -type EndResult = {finished: bool}; +type EndResult = {finished: boolean}; type EndCallback = (result: EndResult) => void; type EventMapping = { - nativeEventPath: Array; - animatedValueTag: number; + nativeEventPath: Array, + animatedValueTag: number, }; let nativeEventEmitter; @@ -178,6 +178,10 @@ function assertNativeAnimatedModule(): void { invariant(NativeAnimatedModule, 'Native animated module is not available'); } +function isNativeAnimatedAvailable(): boolean { + return !!NativeAnimatedModule; +} + module.exports = { API, validateProps, @@ -187,6 +191,7 @@ module.exports = { generateNewNodeTag, generateNewAnimationId, assertNativeAnimatedModule, + isNativeAnimatedAvailable, get nativeEventEmitter() { if (!nativeEventEmitter) { nativeEventEmitter = new NativeEventEmitter(NativeAnimatedModule);