强制调用 UIView animateWithDuration 完成块

Posted

技术标签:

【中文标题】强制调用 UIView animateWithDuration 完成块【英文标题】:Force UIView animateWithDuration completion block to be called 【发布时间】:2017-02-14 19:17:56 【问题描述】:

我有两个重叠的动画,由于我设置方法的方式,导致第二个不触发。我在方法的开头有这样的检查:

- (void)animateHidden:(BOOL)hidden duration:(CGFloat)seconds delay:(CGFloat)delay options:(UIViewAnimationOptions)options disableUserInteraction:(BOOL)disableUserInteraction 
    if (self.hidden == hidden) 
        return;
    

然后,再往下,我的动画块看起来像这样:

__weak UIView *weakSelf = self;
[UIView animateWithDuration:seconds delay:delay options:options animations:^
    weakSelf.alpha = hidden ? 0 : 1;
 completion:^(BOOL finished) 
    // Return user interaction to previous state
    if (disableUserInteraction) 
        weakSelf.userInteractionEnabled = userInteractionEnabled;
    
    weakSelf.hidden = hidden;
];

两个动画在同一个视图上启动,一个在服务调用之前,一个在服务调用之后。如果服务调用发生得足够快以至于视图仍在动画中,weakSelf.hidden = hidden; 将永远不会被调用,并且第二个动画将退出,因为hidden 的值没有及时更新。

无论如何我可以强制调用animation 块上的完成块吗?在进行检查之前,我需要更新我的 hidden 属性,但找不到完成此操作的方法。

不幸的是,致电[self.layer removeAllAnimations] 似乎不起作用。

【问题讨论】:

不确定您在这些方法中还可以做什么,但是...如果不使用您的hidden 属性/变量,而是检查.alpha 值,它对您有用吗?这会告诉你动画是否完成。 无论如何都应该调用完成块。你可以做什么?最简单/最快的方法是制作标志并检查是否已经完成。 @DonMag 问题在于,当我们调用此方法时,视图最初可能已隐藏,alpha 为 1,因此检查与对应的 alphahidden 值不适用于所有视图。 【参考方案1】:

你可以用CABasicAnimation代替UIView动画,这样会更准确的解决问题。

你可以像这样使用它:

CABasicAnimation* opacityZero= [CABasicAnimation animationWithKeyPath:@"opacity"];
[opacityZero setToValue:[NSNumber numberWithFloat:0.0]];
[opacityZero setDuration:duration];
[[self layer] addAnimation:opacityZero forKey:@"opacityZero"];

当您的服务调用结束时,您可以致电[self.layer removeAllAnimations];

同样,您可以设置不透明度,并根据需要调整上述方法。

您可以找到更多信息here。

【讨论】:

【参考方案2】:

hidden 为前缀的__block 属性声明应该会有所帮助。 比如,@property (nonatomic) __block BOOL hidden;

【讨论】:

不幸的是,这是在扩展中,所以我无法添加任何存储的属性。【参考方案3】:

如果您的目标是 ios 10+,请查看 UIViewPropertyAnimator https://developer.apple.com/reference/uikit/uiviewpropertyanimator?language=objc

结合 UIViewAnimating 和 UIViewImplicitlyAnimating 协议,可以对动画进行修改/中断/暂停/恢复/停止等。

基本示例(IB 中设置的按钮和视图):

- (IBAction)startTapped:(id)sender 

    _myAnimator = [UIViewPropertyAnimator
                   runningPropertyAnimatorWithDuration:3.0
                   delay:0.0
                   options:UIViewAnimationOptionCurveLinear
                   animations:^
                       _theRedBox.alpha = _theRedBox.alpha > 0 ? 0 : 1;
                    completion:^(UIViewAnimatingPosition finalPosition) 
                       // do stuff
                   ];



- (IBAction)stopTapped:(id)sender 

    [_myAnimator stopAnimation:NO];
    [_myAnimator finishAnimationAtPosition:UIViewAnimatingPositionEnd];


【讨论】:

以上是关于强制调用 UIView animateWithDuration 完成块的主要内容,如果未能解决你的问题,请参考以下文章

如何调整 UIView 的大小并强制其子视图调整大小

UIView 实时强制重绘(绘图应用)

在缩放/变换上强制重绘 UIView 或 CALayer

使用自动布局强制 UITableView 中的 UIView 填满屏幕

Swift 3:从“UIView”隐式强制表达的表达式?去任何

动画 UIView setFrame 在每个动画帧上强制 drawRect