如何在单独的动画中将CGAffineTransform链接在一起?

时间:2016-02-25 16:11:51

标签: ios objective-c cocoa-touch animation cgaffinetransform

我在UIView上需要两个动画:

  1. 让视图向下移动并稍微增长。
  2. 让视野在新中心变得更大。
  3. 当我尝试这样做时,第二个动画在一个奇怪的位置开始,但最终位于正确的位置和大小。如何让第二个动画从第一个动画结束的相同位置开始?

    right click and Zap Cache

    #import "ViewController.h"
    
    static const CGFloat kStartX = 100.0;
    static const CGFloat kStartY = 20.0;
    static const CGFloat kStartSize = 30.0;
    static const CGFloat kEndCenterY = 200.0;
    
    @interface ViewController ()
    
    @property (nonatomic, strong) UIView *box;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
      [super viewDidLoad];
    
      self.box = [[UIView alloc] initWithFrame:CGRectMake(kStartX, kStartY, kStartSize, kStartSize)];
      self.box.backgroundColor = [UIColor brownColor];
      [self.view addSubview:self.box];
    
      [UIView animateWithDuration:2.0
                            delay:1.0
           usingSpringWithDamping:1.0
            initialSpringVelocity:0.0
                          options:0
                       animations:^{
                         self.box.transform = [self _transformForSize:50.0 centerY:kEndCenterY];
                       }
                       completion:^(BOOL finished) {
                         [UIView animateWithDuration:2.0
                                               delay:1.0
                              usingSpringWithDamping:1.0
                               initialSpringVelocity:0.0
                                             options:0
                                          animations:^{
                                            self.box.transform = [self _transformForSize:100.0 centerY:kEndCenterY];
                                          }
                                          completion:^(BOOL finished) {
                                          }];
                       }];
    }
    
    - (CGAffineTransform)_transformForSize:(CGFloat)newSize centerY:(CGFloat)newCenterY
    {
      CGFloat newScale = newSize / kStartSize;
      CGFloat startCenterY = kStartY + kStartSize / 2.0;
      CGFloat deltaY = newCenterY - startCenterY;
      CGAffineTransform translation = CGAffineTransformMakeTranslation(0.0, deltaY);
      CGAffineTransform scaling = CGAffineTransformMakeScale(newScale, newScale);
      return CGAffineTransformConcat(scaling, translation);
    }
    
    @end
    

    有一点需要注意:我被迫使用setTransform而不是setFrame。我在我的真实代码中没有使用棕色盒子。我的真实代码是使用复杂的UIView子类,当我使用setFrame时,它不能平滑地缩放。

1 个答案:

答案 0 :(得分:0)

这看起来像可能是一个UIKit错误,当你在现有的转换上应用转换时,UIViews如何解析它们的布局。通过在第二个完成块的最开始执行以下操作,我能够至少获得第二个动画的起始坐标:

  [UIView animateWithDuration:2.0
                        delay:1.0
       usingSpringWithDamping:1.0
        initialSpringVelocity:0.0
                      options:0
                   animations:^{
                     self.box.transform = [self _transformForSize:50.0 centerY:kEndCenterY];
                   }
                   completion:^(BOOL finished) {
                     // <new code here>
                     CGRect newFrame = self.box.frame;
                     self.box.transform = CGAffineTransformIdentity;
                     self.box.frame = newFrame;
                     // </new code>
                     [UIView animateWithDuration:2.0
                                           delay:1.0
                          usingSpringWithDamping:1.0
                           initialSpringVelocity:0.0
                                         options:0
                                      animations:^{
                                        self.box.transform = [self _transformForSize:100.0 centerY:kEndCenterY];
                                      }
                                      completion:^(BOOL finished) {
                                      }];
                   }];

-_transformForSize:centerY:使用相同的调用会导致在第二个动画中执行相同的Y平移,因此在完成所有操作后,该框在视图中的结尾比您想要的更深。

要解决此问题,您需要根据第一个动画的 end 处的框起始Y坐标而不是原始的常量Y坐标来计算deltaY:

- (CGAffineTransform)_transformForSize:(CGFloat)newSize centerY:(CGFloat)newCenterY
{
  CGFloat newScale = newSize / kStartSize;
  // Replace this line:
  CGFloat startCenterY = kStartY + kStartSize / 2.0;
  // With this one:
  CGFloat startCenterY = self.box.frame.origin.y + self.box.frame.size.height / 2.0;
  // </replace>
  CGFloat deltaY = newCenterY - startCenterY;
  CGAffineTransform translation = CGAffineTransformMakeTranslation(0.0, deltaY);
  CGAffineTransform scaling = CGAffineTransformMakeScale(newScale, newScale);
  return CGAffineTransformConcat(scaling, translation);
}

它应该可以解决问题。

<强>更新

我应该说,我认为这是&#34;技巧&#34;更多的是解决方案而不是实际的解决方案,但是框的框架和转换在动画流水线的每个阶段看起来都是正确的,所以如果有一个真正的解决方案&#34;它此刻正在躲避我。这个技巧至少可以解决您的翻译问题,因此您可以尝试更复杂的视图层次结构,看看您能获得多少。