2017-07-03 23:13:34 +00:00
|
|
|
/**
|
2018-09-11 22:27:47 +00:00
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
2017-07-03 23:13:34 +00:00
|
|
|
*
|
2018-02-17 02:24:55 +00:00
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
2017-07-03 23:13:34 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#import "RCTLayoutAnimation.h"
|
|
|
|
|
|
|
|
#import "RCTConvert.h"
|
|
|
|
|
|
|
|
@implementation RCTLayoutAnimation
|
|
|
|
|
|
|
|
static UIViewAnimationCurve _currentKeyboardAnimationCurve;
|
|
|
|
|
|
|
|
static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnimationType type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case RCTAnimationTypeLinear:
|
|
|
|
return UIViewAnimationOptionCurveLinear;
|
|
|
|
case RCTAnimationTypeEaseIn:
|
|
|
|
return UIViewAnimationOptionCurveEaseIn;
|
|
|
|
case RCTAnimationTypeEaseOut:
|
|
|
|
return UIViewAnimationOptionCurveEaseOut;
|
|
|
|
case RCTAnimationTypeEaseInEaseOut:
|
|
|
|
return UIViewAnimationOptionCurveEaseInOut;
|
|
|
|
case RCTAnimationTypeKeyboard:
|
|
|
|
// http://stackoverflow.com/questions/18870447/how-to-use-the-default-ios7-uianimation-curve
|
|
|
|
return (UIViewAnimationOptions)(_currentKeyboardAnimationCurve << 16);
|
|
|
|
default:
|
2017-09-25 17:23:02 +00:00
|
|
|
RCTLogError(@"Unsupported animation type %lld", (long long)type);
|
2017-07-03 23:13:34 +00:00
|
|
|
return UIViewAnimationOptionCurveEaseInOut;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use a custom initialization function rather than implementing `+initialize` so that we can control
|
|
|
|
// when the initialization code runs. `+initialize` runs immediately before the first message is sent
|
|
|
|
// to the class which may be too late for us. By this time, we may have missed some
|
|
|
|
// `UIKeyboardWillChangeFrameNotification`s.
|
|
|
|
+ (void)initializeStatics
|
|
|
|
{
|
|
|
|
#if !TARGET_OS_TV
|
|
|
|
static dispatch_once_t onceToken;
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
|
|
selector:@selector(keyboardWillChangeFrame:)
|
|
|
|
name:UIKeyboardWillChangeFrameNotification
|
|
|
|
object:nil];
|
|
|
|
});
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (void)keyboardWillChangeFrame:(NSNotification *)notification
|
|
|
|
{
|
|
|
|
#if !TARGET_OS_TV
|
|
|
|
NSDictionary *userInfo = notification.userInfo;
|
|
|
|
_currentKeyboardAnimationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
- (instancetype)initWithDuration:(NSTimeInterval)duration
|
|
|
|
delay:(NSTimeInterval)delay
|
|
|
|
property:(NSString *)property
|
|
|
|
springDamping:(CGFloat)springDamping
|
|
|
|
initialVelocity:(CGFloat)initialVelocity
|
|
|
|
animationType:(RCTAnimationType)animationType
|
|
|
|
{
|
|
|
|
if (self = [super init]) {
|
|
|
|
_duration = duration;
|
|
|
|
_delay = delay;
|
|
|
|
_property = property;
|
|
|
|
_springDamping = springDamping;
|
|
|
|
_initialVelocity = initialVelocity;
|
|
|
|
_animationType = animationType;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (instancetype)initWithDuration:(NSTimeInterval)duration
|
|
|
|
config:(NSDictionary *)config
|
|
|
|
{
|
|
|
|
if (!config) {
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self = [super init]) {
|
|
|
|
_property = [RCTConvert NSString:config[@"property"]];
|
|
|
|
|
|
|
|
_duration = [RCTConvert NSTimeInterval:config[@"duration"]] ?: duration;
|
|
|
|
if (_duration > 0.0 && _duration < 0.01) {
|
|
|
|
RCTLogError(@"RCTLayoutAnimationGroup expects timings to be in ms, not seconds.");
|
|
|
|
_duration = _duration * 1000.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_delay = [RCTConvert NSTimeInterval:config[@"delay"]];
|
|
|
|
if (_delay > 0.0 && _delay < 0.01) {
|
|
|
|
RCTLogError(@"RCTLayoutAnimationGroup expects timings to be in ms, not seconds.");
|
|
|
|
_delay = _delay * 1000.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_animationType = [RCTConvert RCTAnimationType:config[@"type"]];
|
|
|
|
if (_animationType == RCTAnimationTypeSpring) {
|
|
|
|
_springDamping = [RCTConvert CGFloat:config[@"springDamping"]];
|
|
|
|
_initialVelocity = [RCTConvert CGFloat:config[@"initialVelocity"]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)performAnimations:(void (^)(void))animations
|
|
|
|
withCompletionBlock:(void (^)(BOOL completed))completionBlock
|
|
|
|
{
|
|
|
|
if (_animationType == RCTAnimationTypeSpring) {
|
|
|
|
[UIView animateWithDuration:_duration
|
|
|
|
delay:_delay
|
|
|
|
usingSpringWithDamping:_springDamping
|
|
|
|
initialSpringVelocity:_initialVelocity
|
|
|
|
options:UIViewAnimationOptionBeginFromCurrentState
|
|
|
|
animations:animations
|
|
|
|
completion:completionBlock];
|
|
|
|
} else {
|
|
|
|
UIViewAnimationOptions options =
|
|
|
|
UIViewAnimationOptionBeginFromCurrentState |
|
|
|
|
UIViewAnimationOptionsFromRCTAnimationType(_animationType);
|
|
|
|
|
|
|
|
[UIView animateWithDuration:_duration
|
|
|
|
delay:_delay
|
|
|
|
options:options
|
|
|
|
animations:animations
|
|
|
|
completion:completionBlock];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isEqual:(RCTLayoutAnimation *)animation
|
|
|
|
{
|
|
|
|
return
|
|
|
|
_duration == animation.duration &&
|
|
|
|
_delay == animation.delay &&
|
|
|
|
(_property == animation.property || [_property isEqualToString:animation.property]) &&
|
|
|
|
_springDamping == animation.springDamping &&
|
|
|
|
_initialVelocity == animation.initialVelocity &&
|
|
|
|
_animationType == animation.animationType;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)description
|
|
|
|
{
|
|
|
|
return [NSString stringWithFormat:@"<%@: %p; duration: %f; delay: %f; property: %@; springDamping: %f; initialVelocity: %f; animationType: %li;>",
|
|
|
|
NSStringFromClass([self class]), self, _duration, _delay, _property, _springDamping, _initialVelocity, (long)_animationType];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|