Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions Examples/UIExplorer/js/NativeAnimationsProblemExample.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @flow
*/
'use strict';

var React = require('react');
var ReactNative = require('react-native');
var {
View,
Text,
Animated,
StyleSheet,
TouchableWithoutFeedback,
} = ReactNative;

class Tester extends React.Component {

static title = 'Native Animated Problem';
static description = 'Test out Native Animations';

state = {
opacity: new Animated.Value(0.25, {useNativeDriver: true}),
showBlock2: false,
};

visible = false;

runAnimation = () => {
this.visible = !this.visible;
Animated.timing(this.state.opacity, {
toValue: this.visible ? 1 : 0.25,
duration: 500,
useNativeDriver: true,
}).start();
};

render() {
return (
<View style={styles.container}>
<View style={styles.section}>
<TouchableWithoutFeedback onPress={this.runAnimation}>
<View style={styles.button}>
<Text>{'Run animation'}</Text>
</View>
</TouchableWithoutFeedback>
</View>
<View style={styles.section}>
<TouchableWithoutFeedback onPress={() => {
this.setState({
showBlock2: !this.state.showBlock2,
});
}}>
<View style={styles.button}>
<Text>{'Toggle block 2'}</Text>
</View>
</TouchableWithoutFeedback>
</View>
<View style={styles.section}>
{this._renderBlock(1)}
</View>
<View style={styles.section}>
{this.state.showBlock2 && this._renderBlock(2)}
</View>
</View>
);
}

_renderBlock(key: number) {
return (
<Animated.View
key={key}
style={[
styles.block,
{
opacity: this.state.opacity,
}
]}
/>
);
}
}

const styles = StyleSheet.create({
container: {
padding: 10,
},
button: {
padding: 10,
backgroundColor: 'green',
},
section: {
marginBottom: 20,
},
block: {
width: 50,
height: 50,
backgroundColor: 'blue',
},
});

module.exports = Tester;
4 changes: 4 additions & 0 deletions Examples/UIExplorer/js/UIExplorerList.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ const APIExamples: Array<UIExplorerExample> = [
key: 'NativeAnimationsExample',
module: require('./NativeAnimationsExample'),
},
{
key: 'NativeAnimationsProblemExample',
module: require('./NativeAnimationsProblemExample'),
},
{
key: 'NavigationExperimentalExample',
module: require('./NavigationExperimental/NavigationExperimentalExample'),
Expand Down
4 changes: 4 additions & 0 deletions Examples/UIExplorer/js/UIExplorerList.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ const APIExamples: Array<UIExplorerExample> = [
key: 'NativeAnimationsExample',
module: require('./NativeAnimationsExample'),
},
{
key: 'NativeAnimationsProblemExample',
module: require('./NativeAnimationsProblemExample'),
},
{
key: 'NavigationExperimentalExample',
module: require('./NavigationExperimental/NavigationExperimentalExample'),
Expand Down
14 changes: 12 additions & 2 deletions Libraries/Animated/src/AnimatedImplementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,10 @@ class SpringAnimation extends Animation {
}
}

type AnimatedValueConfig = {
useNativeDriver?: bool;
};

type ValueListenerCallback = (state: {value: number}) => void;

var _uniqueId = 1;
Expand All @@ -678,12 +682,15 @@ class AnimatedValue extends AnimatedWithChildren {
_listeners: {[key: string]: ValueListenerCallback};
__nativeAnimatedValueListener: ?any;

constructor(value: number) {
constructor(value: number, config?: AnimatedValueConfig) {
super();
this._startingValue = this._value = value;
this._offset = 0;
this._animation = null;
this._listeners = {};
if (config && config.useNativeDriver) {
this.__makeNative();
}
}

__detach() {
Expand Down Expand Up @@ -929,7 +936,7 @@ class AnimatedValueXY extends AnimatedWithChildren {
y: AnimatedValue;
_listeners: {[key: string]: {x: string, y: string}};

constructor(valueIn?: ?{x: number | AnimatedValue, y: number | AnimatedValue}) {
constructor(valueIn?: ?{x: number | AnimatedValue; y: number | AnimatedValue}, config?: AnimatedValueConfig) {
super();
var value: any = valueIn || {x: 0, y: 0}; // @flowfixme: shouldn't need `: any`
if (typeof value.x === 'number' && typeof value.y === 'number') {
Expand All @@ -946,6 +953,9 @@ class AnimatedValueXY extends AnimatedWithChildren {
this.y = value.y;
}
this._listeners = {};
if (config && config.useNativeDriver) {
this.__makeNative();
}
}

setValue(value: {x: number, y: number}) {
Expand Down
1 change: 0 additions & 1 deletion Libraries/NativeAnimation/Nodes/RCTAnimatedNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
@property (nonatomic, copy, readonly) NSDictionary<NSNumber *, RCTAnimatedNode *> *parentNodes;

@property (nonatomic, readonly) BOOL needsUpdate;
@property (nonatomic, readonly) BOOL hasUpdated;

/**
* Marks a node and its children as needing update.
Expand Down
14 changes: 5 additions & 9 deletions Libraries/NativeAnimation/Nodes/RCTAnimatedNode.m
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ - (void)onAttachedToNode:(RCTAnimatedNode *)parent
if (parent) {
_parentNodes[parent.nodeTag] = parent;
}
[self setNeedsUpdate];
}

- (void)onDetachedFromNode:(RCTAnimatedNode *)parent
Expand All @@ -79,6 +80,7 @@ - (void)onDetachedFromNode:(RCTAnimatedNode *)parent
if (parent) {
[_parentNodes removeObjectForKey:parent.nodeTag];
}
[self setNeedsUpdate];
}

- (void)detachNode
Expand All @@ -93,10 +95,6 @@ - (void)detachNode

- (void)setNeedsUpdate
{
if (_needsUpdate) {
// Has already been marked. Stop branch.
return;
}
_needsUpdate = YES;
for (RCTAnimatedNode *child in _childNodes.allValues) {
[child setNeedsUpdate];
Expand All @@ -105,9 +103,7 @@ - (void)setNeedsUpdate

- (void)cleanupAnimationUpdate
{
if (_hasUpdated) {
_needsUpdate = NO;
_hasUpdated = NO;
if (!_needsUpdate) {
for (RCTAnimatedNode *child in _childNodes.allValues) {
[child cleanupAnimationUpdate];
}
Expand All @@ -116,7 +112,7 @@ - (void)cleanupAnimationUpdate

- (void)updateNodeIfNecessary
{
if (_needsUpdate && !_hasUpdated) {
if (_needsUpdate) {
for (RCTAnimatedNode *parent in _parentNodes.allValues) {
[parent updateNodeIfNecessary];
}
Expand All @@ -126,7 +122,7 @@ - (void)updateNodeIfNecessary

- (void)performUpdate
{
_hasUpdated = YES;
_needsUpdate = NO;
// To be overidden by subclasses
// This method is called on a node only if it has been marked for update
// during the current update loop
Expand Down
2 changes: 1 addition & 1 deletion Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ - (void)performUpdate
NSDictionary<NSString *, NSNumber *> *style = self.config[@"style"];
[style enumerateKeysAndObjectsUsingBlock:^(NSString *property, NSNumber *nodeTag, __unused BOOL *stop) {
RCTAnimatedNode *node = self.parentNodes[nodeTag];
if (node && node.hasUpdated) {
if (node) {
if ([node isKindOfClass:[RCTValueAnimatedNode class]]) {
RCTValueAnimatedNode *parentNode = (RCTValueAnimatedNode *)node;
[self->_updatedPropsDictionary setObject:@(parentNode.value) forKey:property];
Expand Down
2 changes: 1 addition & 1 deletion Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ - (void)performUpdate
NSNumber *nodeTag = transformConfig[@"nodeTag"];

RCTAnimatedNode *node = self.parentNodes[nodeTag];
if (node.hasUpdated && [node isKindOfClass:[RCTValueAnimatedNode class]]) {
if ([node isKindOfClass:[RCTValueAnimatedNode class]]) {
RCTValueAnimatedNode *parentNode = (RCTValueAnimatedNode *)node;

NSString *property = transformConfig[@"property"];
Expand Down
1 change: 1 addition & 0 deletions Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ - (instancetype)initWithTag:(NSNumber *)tag
_value = [self.config[@"value"] floatValue];
}
return self;

}

- (void)flattenOffset
Expand Down
3 changes: 2 additions & 1 deletion Libraries/NativeAnimation/RCTNativeAnimatedModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ - (void)setBridge:(RCTBridge *)bridge
_propAnimationNodes = [NSMutableSet new];
}


- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
Expand Down Expand Up @@ -218,6 +217,8 @@ - (dispatch_queue_t)methodQueue
if (viewTag && [node isKindOfClass:[RCTPropsAnimatedNode class]]) {
[(RCTPropsAnimatedNode *)node connectToView:viewTag animatedModule:self];
}
[node setNeedsUpdate];
[node updateNodeIfNecessary];
}

RCT_EXPORT_METHOD(disconnectAnimatedNodeFromView:(nonnull NSNumber *)nodeTag
Expand Down