ios – 如何阻止和反转UIView动画?

我已经动画了一个UIView,当用户触摸切换按钮时它会缩小,并且当用户再次触摸按钮时,它会扩展回原来的大小.到目前为止,一切都很好.问题是动画需要一些时间 – 例如3秒.在此期间,我仍然希望用户能够与界面交互.所以当用户在动画仍在进行的同时触摸按钮时,动画应该停在正确的位置并且反向.

在苹果问答中我已经找到一种方法来暂停所有的动画:

https://developer.apple.com/library/ios/#qa/qa2009/qa1673.html

但我没有看到从这里扭转动画的方法(省略了其余的初始动画).我该如何做到这一点?

- (IBAction)toggleMeter:(id)sender {
    if (self.myView.hidden) {        
        self.myView.hidden = NO;
        [UIView animateWithDuration:3 animations:^{
            self.myView.transform = expandMatrix;
        } completion:nil];
    } else {
        [UIView animateWithDuration:3 animations:^{
            self.myView.transform = shrinkMatrix;
        } completion:^(BOOL finished) {
            self.myView.hidden = YES;
        }];
    }
}

解决方法

除了下面(我们从表示层获取当前状态,停止动画,从保存的表示层重置当前状态,并启动新的动画),有一个更容易的解决方案.

如果要执行基于块的动画,如果要在8.0之前的iOS版本中停止动画并启动新的动画,可以使用UIViewAnimationoptionBeginFromCurrentState选项. (在iOS 8中有效,认行为不仅是从当前状态开始,而是以反映当前位置以及当前速度的方式执行此操作,从而使其无需担心此问题请参阅WWDC 2014 video Building Interruptible and Responsive Interactions了解更多信息.)

[UIView animateWithDuration:3.0
                      delay:0.0
                    options:UIViewAnimationoptionBeginFromCurrentState | UIViewAnimationoptionAllowUserInteraction
                 animations:^{
                     // specify the new `frame`,`transform`,etc. here
                 }
                 completion:NULL];

您可以通过停止当前动画并从当前的动画开始新的动画来实现此目的.您可以使用Quartz 2D

> Add QuartzCore.framework to your project如果你还没有(在Xcode的当代版本中,通常不需要明确地这样做,因为它自动链接到项目.)
>如果您还没有(再次,Xcode的当代版本不需要),则导入必要的标题

#import <QuartzCore/QuartzCore.h>

>让你的代码停止现有的动画:

[self.subview.layer removeAllAnimations];

>获取对当前表示层的引用(即视图的状态,正是在此刻):

CALayer *currentLayer = self.subview.layer.presentationLayer;

>根据presentationLayer中的当前值重置变换(或框架或任何内容):

self.subview.layer.transform = currentLayer.transform;

>现在,从该变换(或框架或任何)到新值的动画:

[UIView animateWithDuration:1.0
                      delay:0.0
                    options:UIViewAnimationoptionAllowUserInteraction
                 animations:^{
                     self.subview.layer.transform = newTransform;
                 }
                 completion:NULL];

把这一切都放在一起,这里是一个例程,将我的变换缩放从2.0x切换到识别和返回:

- (IBAction)didTouchUpInsideAnimateButton:(id)sender
{
    CALayer *currentLayer = self.subview.layer.presentationLayer;

    [self.subview.layer removeAllAnimations];

    self.subview.layer.transform = currentLayer.transform;

    CATransform3D newTransform;

    self.large = !self.large;

    if (self.large)
        newTransform = CATransform3DMakeScale(2.0,2.0,1.0);
    else
        newTransform = CATransform3DIdentity;

    [UIView animateWithDuration:1.0
                          delay:0.0
                        options:UIViewAnimationoptionAllowUserInteraction
                     animations:^{
                         self.subview.layer.transform = newTransform;
                     }
                     completion:NULL];
}

或者如果要将帧大小从100×100切换到200×200,然后返回:

- (IBAction)didTouchUpInsideAnimateButton:(id)sender
{
    CALayer *currentLayer = self.subview.layer.presentationLayer;

    [self.subview.layer removeAllAnimations];

    CGRect newFrame = currentLayer.frame;

    self.subview.frame = currentLayer.frame;

    self.large = !self.large;

    if (self.large)
        newFrame.size = CGSizeMake(200.0,200.0);
    else
        newFrame.size = CGSizeMake(100.0,100.0);

    [UIView animateWithDuration:1.0
                          delay:0.0
                        options:UIViewAnimationoptionAllowUserInteraction
                     animations:^{
                         self.subview.frame = newFrame;
                     }
                     completion:NULL];
}

顺便说一句,虽然它对于真正快速的动画来说通常并不重要,但对于像您这样的慢速动画,您可能希望将反转动画的持续时间设置为与您当前动画中进展的距离相同例如,如果你在3.0秒的动画中有0.5秒,当你反转时,你可能不需要花费3.0秒才能扭转你迄今为止所做的一小部分动画,而仅仅是0.5秒).因此,这可能看起来像:

- (IBAction)didTouchUpInsideAnimateButton:(id)sender
{
    CFTimeInterval duration = kAnimationDuration;             // default the duration to some constant
    CFTimeInterval currentMediaTime = CACurrentMediaTime();   // get the current media time
    static CFTimeInterval lastAnimationStart = 0.0;           // media time of last animation (zero the first time)

    // if we prevIoUsly animated,then calculate how far along in the prevIoUs animation we were
    // and we'll use that for the duration of the reversing animation; if larger than
    // kAnimationDuration that means the prior animation was done,so we'll just use
    // kAnimationDuration for the length of this animation

    if (lastAnimationStart)
        duration = MIN(kAnimationDuration,(currentMediaTime - lastAnimationStart));

    // save our media time for future reference (i.e. future invocations of this routine)

    lastAnimationStart = currentMediaTime;

    // if you want the animations to stay relative the same speed if reversing an ongoing
    // reversal,you can backdate the lastAnimationStart to what the lastAnimationStart
    // would have been if it was a full animation; if you don't do this,if you repeatedly
    // reverse a reversal that is still in progress,they'll incrementally speed up.

    if (duration < kAnimationDuration)
        lastAnimationStart -= (kAnimationDuration - duration);

    // grab the state of the layer as it is right Now

    CALayer *currentLayer = self.subview.layer.presentationLayer;

    // cancel any animations in progress

    [self.subview.layer removeAllAnimations];

    // set the transform to be as it is Now,possibly in the middle of an animation

    self.subview.layer.transform = currentLayer.transform;

    // toggle our flag as to whether we're looking at large view or not

    self.large = !self.large;

    // set the transform based upon the state of the `large` boolean

    CATransform3D newTransform;

    if (self.large)
        newTransform = CATransform3DMakeScale(2.0,1.0);
    else
        newTransform = CATransform3DIdentity;

    // Now animate to our new setting

    [UIView animateWithDuration:duration
                          delay:0.0
                        options:UIViewAnimationoptionAllowUserInteraction
                     animations:^{
                         self.subview.layer.transform = newTransform;
                     }
                     completion:NULL];
}

相关文章

UITabBarController 是 iOS 中用于管理和显示选项卡界面的一...
UITableView的重用机制避免了频繁创建和销毁单元格的开销,使...
Objective-C中,类的实例变量(instance variables)和属性(...
从内存管理的角度来看,block可以作为方法的传入参数是因为b...
WKWebView 是 iOS 开发中用于显示网页内容的组件,它是在 iO...
OC中常用的多线程编程技术: 1. NSThread NSThread是Objecti...