It turns out that using UIViewAnimationOptionBeginFromCurrentState does not always work as UIViewAnimationOptionBeginFromCurrentState .
Take a look at this example:
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; UIButton *theButton = [UIButton new]; [self.view addSubview:theButton]; theButton.frame = self.view.frame; theButton.backgroundColor = [UIColor redColor]; theButton.alpha = 0.05; [theButton addTarget:self action:@selector(actionPressed:) forControlEvents:UIControlEventTouchUpInside]; } - (void)actionPressed:(UIButton *)theButton { theButton.alpha = 0.6; [UIView animateWithDuration:5 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^ {
In the above example, you expect .alpha to animate from 0.6 to 1. However, it animates from 0.05 to 1.
To solve the problem, you should change actionPressed: to the following:
- (void)actionPressed:(UIButton *)theButton { [UIView animateWithDuration:0 animations:^ {
Mention animateWithDuration:0 !!!
The rule is easy: use only an animation block with UIViewAnimationOptionBeginFromCurrentState AFTER some other animation block, so that all your previous changes are actually applied.
If you donβt know what exactly should be included in the animateWithDuration:0 block, you can use this trick:
- (void)actionPressed:(UIButton *)theButton {
If you do not want to recall all the details of this error, simply apply the Swizzling method to the UIView class.
IMPORTANT CHANGE: It turned out that the code below will lead to crash at runtime when you call performBatchUpdates:completion: a UICollectionView instance. Therefore, I do not recommend using method swizzling in this case!
Your code might look like this:
+ (void)load { static dispatch_once_t theOnceToken; dispatch_once(&theOnceToken, ^ { Class theClass = object_getClass(self); SEL theOriginalSelector = @selector(animateWithDuration:delay:options:animations:completion:); SEL theSwizzledSelector = @selector(swizzled_animateWithDuration:delay:options:animations:completion:); Method theOriginalMethod = class_getClassMethod(theClass, theOriginalSelector); Method theSwizzledMethod = class_getClassMethod(theClass, theSwizzledSelector); if (!theClass ||!theOriginalSelector || !theSwizzledSelector || !theOriginalMethod || !theSwizzledMethod) { abort(); } BOOL didAddMethod = class_addMethod(theClass, theOriginalSelector, method_getImplementation(theSwizzledMethod), method_getTypeEncoding(theSwizzledMethod)); if (didAddMethod) { class_replaceMethod(theClass, theSwizzledSelector, method_getImplementation(theOriginalMethod), method_getTypeEncoding(theOriginalMethod)); } else { method_exchangeImplementations(theOriginalMethod, theSwizzledMethod); } }); } + (void)swizzled_animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL))completion { if (options & UIViewAnimationOptionBeginFromCurrentState) { UIView *theView = [UIView new]; theView.alpha = 1; [UIView animateWithDuration:0 animations:^ { theView.alpha = 0; } completion:^(BOOL finished) { [self swizzled_animateWithDuration:duration delay:delay options:options animations:animations completion:completion]; }]; } else { [self swizzled_animateWithDuration:duration delay:delay options:options animations:animations completion:completion]; } }
If you add this code to your custom UIView category, then this code will work fine:
- (void)actionPressed:(UIButton *)theButton { theButton.alpha = 0.6; [UIView animateWithDuration:5 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^ {
In my case, this error completely destroyed my animations. See below:
[
] [
]