Prevent Fabric from changing props if they are managed by Animated

Summary:
Changelog: [internal]

# Problem

Fabric doesn't know when NativeAnimatedModule control a prop and overrides its change whenever any prop changes. For example component A is animating its opacity from 1 to 0. NativeAnimatedModule starts calling `[RCTViewComponentView updateProps:oldProps:]` method interpolating opacity from 1 to 0.

After it is finished, if any prop is updated on the component. Its opacity will be set to default.

# Fix

This is a temporary problem until Unified Animation System is put in place. To work around the issue for now, we keep a set of prop keys controlled by animated and only update the prop if it isn't in this list. List is cleared when the component is reused.

Reviewed By: JoshuaGross

Differential Revision: D24046848

fbshipit-source-id: 63cca6854f97b2de764cb3ed505d328323c64525
This commit is contained in:
Samuel Susla
2020-10-01 12:16:08 -07:00
committed by Facebook GitHub Bot
parent 61cfa97067
commit b2c022ec54
5 changed files with 30 additions and 2 deletions
@@ -23,6 +23,7 @@ using namespace facebook::react;
UIColor *_backgroundColor;
CALayer *_borderLayer;
BOOL _needsInvalidateLayer;
NSSet<NSString *> *_propKeysManagedByAnimated;
}
- (instancetype)initWithFrame:(CGRect)frame
@@ -83,6 +84,11 @@ using namespace facebook::react;
return concreteComponentDescriptorProvider<ViewComponentDescriptor>();
}
- (void)setPropKeysManagedByAnimated:(nullable NSSet<NSString *> *)propKeys
{
_propKeysManagedByAnimated = propKeys;
}
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
{
#ifndef NS_BLOCK_ASSERTIONS
@@ -102,7 +108,7 @@ using namespace facebook::react;
BOOL needsInvalidateLayer = NO;
// `opacity`
if (oldViewProps.opacity != newViewProps.opacity) {
if (oldViewProps.opacity != newViewProps.opacity && ![_propKeysManagedByAnimated containsObject:@"opacity"]) {
self.layer.opacity = (CGFloat)newViewProps.opacity;
needsInvalidateLayer = YES;
}
@@ -161,7 +167,7 @@ using namespace facebook::react;
}
// `transform`
if (oldViewProps.transform != newViewProps.transform) {
if (oldViewProps.transform != newViewProps.transform && ![_propKeysManagedByAnimated containsObject:@"transform"]) {
self.layer.transform = RCTCATransform3DFromTransformMatrix(newViewProps.transform);
self.layer.allowsEdgeAntialiasing = newViewProps.transform != Transform::Identity();
}
@@ -286,6 +292,17 @@ using namespace facebook::react;
- (void)prepareForRecycle
{
[super prepareForRecycle];
// If view was managed by animated, its props need to align with UIView's properties.
auto const &props = *std::static_pointer_cast<ViewProps const>(_props);
if ([_propKeysManagedByAnimated containsObject:@"transform"]) {
self.layer.transform = RCTCATransform3DFromTransformMatrix(props.transform);
}
if ([_propKeysManagedByAnimated containsObject:@"opacity"]) {
self.layer.opacity = (CGFloat)props.opacity;
}
_propKeysManagedByAnimated = nil;
_eventEmitter.reset();
}
@@ -116,6 +116,8 @@ typedef NS_OPTIONS(NSInteger, RNComponentViewUpdateMask) {
*/
- (facebook::react::SharedProps)props;
- (void)setPropKeysManagedByAnimated:(nullable NSSet<NSString *> *)propKeys;
@end
NS_ASSUME_NONNULL_END
@@ -222,7 +222,9 @@ static void RCTPerformMountInstructions(
UIView<RCTComponentViewProtocol> *componentView = [_componentViewRegistry findComponentViewWithTag:reactTag];
SharedProps oldProps = [componentView props];
SharedProps newProps = componentDescriptor.cloneProps(oldProps, RawProps(convertIdToFollyDynamic(props)));
[componentView setPropKeysManagedByAnimated:nil];
[componentView updateProps:newProps oldProps:oldProps];
[componentView setPropKeysManagedByAnimated:[NSSet setWithArray:props.allKeys]];
}
- (void)synchronouslyDispatchCommandOnUIThread:(ReactTag)reactTag
@@ -39,6 +39,8 @@ NS_ASSUME_NONNULL_BEGIN
- (facebook::react::SharedProps)props;
- (void)setPropKeysManagedByAnimated:(nullable NSSet<NSString *> *)propKeys;
@end
NS_ASSUME_NONNULL_END
@@ -132,4 +132,9 @@ using namespace facebook::react;
return nullptr;
}
- (void)setPropKeysManagedByAnimated:(nullable NSSet<NSString *> *)propKeys
{
// Default implementation does nothing.
}
@end