mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-03-29 07:48:17 +08:00
Maintain transform order
Summary: This diff addresses the issues raised by kmagiera in https://github.com/facebook/react-native/pull/7884. Transforms should be applied in the order they are defined, just like in `processTransform.js`. A scale applied before a translation, for instance, should give a different result than a translation applied before a scale. We leverage CATransform3D to do the heavy lifting. A concatenated transform is passed all the way to `RCTViewPropertyMapper`. It is compared with the transform currently applied to the view, and if different, applied. The same approach is used for opacity. I think it makes the most sense to do this diffing in `RCTViewPropertyMapper`, as opposed to creating and cleaning up an `_updatedPropsDictionary` each frame in `RCTTransformAnimatedNode` and `RCTStyleAnimatedNode`. The node should keep its full value; applying a minimal set of altered props is an optimization. The higher up this optimization is implemented, the more assumptions it makes. e.g. that there will only ever be a sing Closes https://github.com/facebook/react-native/pull/9050 Differential Revision: D3658139 fbshipit-source-id: ad6286762ef734084cbdf83c9bd9241190302d34
This commit is contained in:
committed by
Facebook Github Bot
parent
b83ccb5749
commit
eb96b7fabc
@@ -1160,21 +1160,24 @@ class AnimatedTransform extends AnimatedWithChildren {
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
var transConfig = {};
|
||||
var transConfigs = [];
|
||||
|
||||
this._transforms.forEach(transform => {
|
||||
for (var key in transform) {
|
||||
var value = transform[key];
|
||||
if (value instanceof Animated) {
|
||||
transConfig[key] = value.__getNativeTag();
|
||||
transConfigs.push({
|
||||
property: key,
|
||||
nodeTag: value.__getNativeTag(),
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
NativeAnimatedHelper.validateTransform(transConfig);
|
||||
NativeAnimatedHelper.validateTransform(transConfigs);
|
||||
return {
|
||||
type: 'transform',
|
||||
transform: transConfig,
|
||||
transforms: transConfigs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,12 @@ var TRANSFORM_WHITELIST = {
|
||||
translateX: true,
|
||||
translateY: true,
|
||||
scale: true,
|
||||
scaleX: true,
|
||||
scaleY: true,
|
||||
rotate: true,
|
||||
rotateX: true,
|
||||
rotateY: true,
|
||||
perspective: true,
|
||||
};
|
||||
|
||||
function validateProps(params: Object): void {
|
||||
@@ -98,12 +103,12 @@ function validateProps(params: Object): void {
|
||||
}
|
||||
}
|
||||
|
||||
function validateTransform(config: Object): void {
|
||||
for (var key in config) {
|
||||
if (!TRANSFORM_WHITELIST.hasOwnProperty(key)) {
|
||||
throw new Error(`Property '${key}' is not supported by native animated module`);
|
||||
function validateTransform(configs: Array<Object>): void {
|
||||
configs.forEach((config) => {
|
||||
if (!TRANSFORM_WHITELIST.hasOwnProperty(config.property)) {
|
||||
throw new Error(`Property '${config.property}' is not supported by native animated module`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function validateStyles(styles: Object): void {
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
|
||||
@interface RCTStyleAnimatedNode : RCTAnimatedNode
|
||||
|
||||
- (NSDictionary<NSString *, NSNumber *> *)updatedPropsDictionary;
|
||||
- (NSDictionary<NSString *, NSObject *> *)updatedPropsDictionary;
|
||||
|
||||
@end
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
@implementation RCTStyleAnimatedNode
|
||||
{
|
||||
NSMutableDictionary<NSString *, NSNumber *> *_updatedPropsDictionary;
|
||||
NSMutableDictionary<NSString *, NSObject *> *_updatedPropsDictionary;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTag:(NSNumber *)tag
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
|
||||
@interface RCTTransformAnimatedNode : RCTAnimatedNode
|
||||
|
||||
- (NSDictionary<NSString *, NSNumber *> *)updatedPropsDictionary;
|
||||
- (NSDictionary<NSString *, NSObject *> *)updatedPropsDictionary;
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
@implementation RCTTransformAnimatedNode
|
||||
{
|
||||
NSMutableDictionary<NSString *, NSNumber *> *_updatedPropsDictionary;
|
||||
NSMutableDictionary<NSString *, NSObject *> *_updatedPropsDictionary;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTag:(NSNumber *)tag
|
||||
@@ -33,14 +33,50 @@
|
||||
{
|
||||
[super performUpdate];
|
||||
|
||||
NSDictionary<NSString *, NSNumber *> *transforms = self.config[@"transform"];
|
||||
[transforms enumerateKeysAndObjectsUsingBlock:^(NSString *property, NSNumber *nodeTag, __unused BOOL *stop) {
|
||||
CATransform3D transform = CATransform3DIdentity;
|
||||
|
||||
NSArray<NSDictionary *> *transformConfigs = self.config[@"transforms"];
|
||||
for (NSDictionary *transformConfig in transformConfigs) {
|
||||
NSNumber *nodeTag = transformConfig[@"nodeTag"];
|
||||
|
||||
RCTAnimatedNode *node = self.parentNodes[nodeTag];
|
||||
if (node.hasUpdated && [node isKindOfClass:[RCTValueAnimatedNode class]]) {
|
||||
RCTValueAnimatedNode *parentNode = (RCTValueAnimatedNode *)node;
|
||||
self->_updatedPropsDictionary[property] = @(parentNode.value);
|
||||
|
||||
NSString *property = transformConfig[@"property"];
|
||||
CGFloat value = parentNode.value;
|
||||
|
||||
if ([property isEqualToString:@"scale"]) {
|
||||
transform = CATransform3DScale(transform, value, value, 1);
|
||||
|
||||
} else if ([property isEqualToString:@"scaleX"]) {
|
||||
transform = CATransform3DScale(transform, value, 1, 1);
|
||||
|
||||
} else if ([property isEqualToString:@"scaleY"]) {
|
||||
transform = CATransform3DScale(transform, 1, value, 1);
|
||||
|
||||
} else if ([property isEqualToString:@"translateX"]) {
|
||||
transform = CATransform3DTranslate(transform, value, 0, 0);
|
||||
|
||||
} else if ([property isEqualToString:@"translateY"]) {
|
||||
transform = CATransform3DTranslate(transform, 0, value, 0);
|
||||
|
||||
} else if ([property isEqualToString:@"rotate"]) {
|
||||
transform = CATransform3DRotate(transform, value, 0, 0, 1);
|
||||
|
||||
} else if ([property isEqualToString:@"rotateX"]) {
|
||||
transform = CATransform3DRotate(transform, value, 1, 0, 0);
|
||||
|
||||
} else if ([property isEqualToString:@"rotateY"]) {
|
||||
transform = CATransform3DRotate(transform, value, 0, 1, 0);
|
||||
|
||||
} else if ([property isEqualToString:@"perspective"]) {
|
||||
transform.m34 = 1.0 / -value;
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
_updatedPropsDictionary[@"transform"] = [NSValue valueWithCATransform3D:transform];
|
||||
}
|
||||
|
||||
- (void)cleanupAnimationUpdate
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RCTNativeAnimatedModule;
|
||||
@@ -17,6 +18,6 @@
|
||||
- (instancetype)initWithViewTag:(NSNumber *)viewTag
|
||||
animationModule:(RCTNativeAnimatedModule *)animationModule NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)updateViewWithDictionary:(NSDictionary<NSString *, NSNumber *> *)updates;
|
||||
- (void)updateViewWithDictionary:(NSDictionary<NSString *, NSObject *> *)updates;
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,16 +12,12 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTUIManager.h"
|
||||
#import "RCTNativeAnimatedModule.h"
|
||||
|
||||
@implementation RCTViewPropertyMapper
|
||||
{
|
||||
CGFloat _translateX;
|
||||
CGFloat _translateY;
|
||||
CGFloat _scaleX;
|
||||
CGFloat _scaleY;
|
||||
CGFloat _rotation;
|
||||
RCTNativeAnimatedModule *_animationModule;
|
||||
}
|
||||
|
||||
@@ -31,63 +27,33 @@
|
||||
if ((self = [super init])) {
|
||||
_animationModule = animationModule;
|
||||
_viewTag = viewTag;
|
||||
_translateX = 0;
|
||||
_translateY = 0;
|
||||
_scaleX = 1;
|
||||
_scaleY = 1;
|
||||
_rotation = 0;
|
||||
_animationModule = animationModule;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
|
||||
- (void)updateViewWithDictionary:(NSDictionary<NSString *, NSNumber *> *)updates
|
||||
- (void)updateViewWithDictionary:(NSDictionary<NSString *, NSObject *> *)updates
|
||||
{
|
||||
if (updates.count) {
|
||||
UIView *view = [_animationModule.bridge.uiManager viewForReactTag:_viewTag];
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
if (!updates.count) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSNumber *opacity = updates[@"opacity"];
|
||||
if (opacity) {
|
||||
view.alpha = opacity.doubleValue;
|
||||
}
|
||||
UIView *view = [_animationModule.bridge.uiManager viewForReactTag:_viewTag];
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSNumber *scale = updates[@"scale"];
|
||||
if (scale) {
|
||||
_scaleX = scale.doubleValue;
|
||||
_scaleY = scale.doubleValue;
|
||||
}
|
||||
NSNumber *scaleX = updates[@"scaleX"];
|
||||
if (scaleX) {
|
||||
_scaleX = scaleX.doubleValue;
|
||||
}
|
||||
NSNumber *scaleY = updates[@"scaleY"];
|
||||
if (scaleY) {
|
||||
_scaleY = scaleY.doubleValue;
|
||||
}
|
||||
NSNumber *translateX = updates[@"translateX"];
|
||||
if (translateX) {
|
||||
_translateX = translateX.doubleValue;
|
||||
}
|
||||
NSNumber *translateY = updates[@"translateY"];
|
||||
if (translateY) {
|
||||
_translateY = translateY.doubleValue;
|
||||
}
|
||||
NSNumber *rotation = updates[@"rotate"];
|
||||
if (rotation) {
|
||||
_rotation = rotation.doubleValue;
|
||||
}
|
||||
NSNumber *opacity = [RCTConvert NSNumber:updates[@"opacity"]];
|
||||
if (opacity) {
|
||||
view.alpha = opacity.floatValue;
|
||||
}
|
||||
|
||||
if (translateX || translateY || scale || scaleX || scaleY || rotation) {
|
||||
CATransform3D xform = CATransform3DMakeScale(_scaleX, _scaleY, 0);
|
||||
xform = CATransform3DTranslate(xform, _translateX, _translateY, 0);
|
||||
xform = CATransform3DRotate(xform, _rotation, 0, 0, 1);
|
||||
view.layer.allowsEdgeAntialiasing = YES;
|
||||
view.layer.transform = xform;
|
||||
}
|
||||
NSObject *transform = updates[@"transform"];
|
||||
if ([transform isKindOfClass:[NSValue class]]) {
|
||||
view.layer.allowsEdgeAntialiasing = YES;
|
||||
view.layer.transform = ((NSValue *)transform).CATransform3DValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user