【问题标题】:Trouble with CAAnimationCAAnimation 的问题
【发布时间】:2012-12-06 14:56:52
【问题描述】:

//卡片类的头文件

#import "OWCardView.h"

@implementation OWCardView;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.layer.contents      = (id) [UIImage imageNamed:@"4.png"].CGImage;
        self.layer.shadowColor   = [UIColor whiteColor].CGColor;
        self.layer.shadowOpacity = 0.3;
    }
    return self;
}


- (void) moveCard:(float)xPoint along:(float)yPoint
{
    CGRect someRect = CGRectMake(xPoint, yPoint, 72, 96);

    [UIView animateWithDuration: 3.5
                          delay: 0.3
                        options: UIViewAnimationCurveEaseOut
                     animations: ^{ self.frame = someRect;}
                     completion: ^(BOOL finished) { }];
}


@end


// part of the Implementation in the view controller's viewDidLoad

[...]
     CGRect myImageRect = CGRectMake(20.0f, 20.0f, 72.0f, 96.0f);

     // myCard is a property of the viewController
     self.myCard = [[OWCardView alloc] initWithFrame:myImageRect];
     [self.view addSubview:self.myCard];
     [self.myCard moveCard: 240 along: 355];     // First call
     [self.myCard moveCard: 50 along: 355];      // Second call
     [self.myCard moveCard: 50 along: 50];       // Third call
[...]

问题: 仅执行 viewController 中 moveCard 的最后一条消息;第一次和第二次调用不执行。代码有什么问题?

当我将第三条消息注释到 moveCard 时,第二个调用被执行而第一个没有。如果我评论第二个和第三个调用,则执行第一个调用。但我希望卡片上出现所有三个动画。

【问题讨论】:

    标签: iphone objective-c ios uiview core-animation


    【解决方案1】:

    当您为视图设置动画时,您应用到该视图的任何先前动画都会立即取消,即使任一动画具有非零延迟。因此,如果要应用顺序动画,则必须在第一个动画结束后添加第二个动画。您可以使用完成块来检测第一个动画何时结束。

    moveCard:along: 维护一个目标矩形队列并按顺序应用动画非常容易:

    @implementation OWCardView {
        NSMutableArray *pendingRects;
        BOOL isAnimating;
    }
    
    - (void)moveCard:(float)xPoint along:(float)yPoint {
        CGRect someRect = CGRectMake(xPoint, yPoint, 72, 96);
        if (!pendingRects) {
            pendingRects = [NSMutableArray array];
        }
        [pendingRects addObject:[NSValue valueWithCGRect:someRect]];
        [self startAnimatingIfNeeded];
    }
    
    - (void)startAnimatingIfNeeded {
        if (isAnimating)
            return;
        if (pendingRects.count == 0)
            return;
        CGRect rect = [[pendingRects objectAtIndex:0] CGRectValue];
        [pendingRects removeObjectAtIndex:0];
    
        isAnimating = YES;
        [UIView animateWithDuration:3.5 delay:0.3 options:UIViewAnimationCurveEaseOut animations:^{
            self.frame = rect;
        } completion:^(BOOL finished) {
            isAnimating = NO;
            [self startAnimatingIfNeeded];
        }];
    }
    

    【讨论】:

      【解决方案2】:

      第三个动画覆盖第一个和第二个

      你可以用这个

      - (void) moveCard:(CGPoint)Point1 point2:(CGPoint)Point2 point3:(CGPoint)Point3
      {
          CGRect someRect = CGRectMake(Point2.x, Point2.y, 72, 96);
      
          [UIView animateWithDuration: 3.5
                                delay: 0.3
                              options: UIViewAnimationCurveEaseOut
                           animations: ^{ self.frame = someRect;}
                           completion: ^(BOOL finished) {
                               someRect = CGRectMake(Point2.x, Point2.y, 72, 96);
                               [UIView animateWithDuration: 3.5
                                                     delay: 0.3
                                                   options: UIViewAnimationCurveEaseOut
                                                animations: ^{ self.frame = someRect;}
                                                completion: ^(BOOL finished) {
      
                                                    someRect = CGRectMake(Point3.x, Point3.y, 72, 96);
                                                    [UIView animateWithDuration: 3.5
                                                                          delay: 0.3
                                                                        options: UIViewAnimationCurveEaseOut
                                                                     animations: ^{ self.frame = someRect;}
                                                                     completion: ^(BOOL finished) {
      
      
      
                                                                     }];
      
                                                }];
      
                           }];
      }
      

      【讨论】:

      • 这行不通。您使用的点不正确。此外,如果动画总是相同的(看起来就是这样),那么整个过程就过于复杂了。
      • 也许你有权利,这种方法使过程过于复杂,但我在这种情况下工作。以任何方式感谢您的宝贵意见
      【解决方案3】:

      你的问题是动画是异步的。

      在执行下一个动画之前,代码不会等待每个动画完成。所以它会通过前两个调用并立即开始第三个动画并取消前两个,这意味着您只会看到最后一个动画。

      动画结束后,你必须使用完成的块来做一些事情。

      简单的方法就是这样......

      [UIView animateWithDuration: 3.5
                            delay: 0.3
                          options: UIViewAnimationCurveEaseOut
                       animations: ^{ self.frame = CGRectMake(240, 355, 72, 96);}
                       completion: ^(BOOL finished) {
          [UIView animateWithDuration: 3.5
                                delay: 0.3
                              options: UIViewAnimationCurveEaseOut
                           animations: ^{ self.frame = CGRectMake(50, 355, 72, 96);}
                           completion: ^(BOOL finished) {
              [UIView animateWithDuration: 3.5
                                    delay: 0.3
                                  options: UIViewAnimationCurveEaseOut
                               animations: ^{ self.frame = CGRectMake(50, 50, 72, 96);}
                               completion: ^(BOOL finished) {
                  //All finished
              }];
          }];
      }];
      

      您可以将其放入某种递归函数中,但这样做可能更容易。

      另一种选择是使用关键帧动画,您可以逐步建立路径和时间,然后说“开始”,它会执行您建立的动画。

      不过现在这可能更容易,我以前用过这种东西。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-23
        • 1970-01-01
        • 1970-01-01
        • 2012-03-09
        • 1970-01-01
        相关资源
        最近更新 更多