【问题标题】:Problems with creating a Ken-Burns Effect创建 Ken-Burns 效果的问题
【发布时间】:2011-09-08 07:46:28
【问题描述】:

我目前正在尝试在 UIImageView 上创建 Ken Burns effect。它首先应该放大(缓慢),然后,动画的 didStopSelector 应该调用一个方法,该方法应该缩小。问题是,只要我不将 didStopSelector 添加到动画中,第一个动画(放大)就可以并且完美地工作。如果我这样做,似乎该方法被直接调用(而不是在它 didStop 之后)。

这是包含动画的 2 种方法:

- (void)beginKenBurnsEffect {

    [UIView beginAnimations:@"a" context:self.view_image];
    [UIView setAnimationCurve:UIViewAnimationCurveLinear];
    [UIView setAnimationDuration:5];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDidStopSelector:@selector(endKenBurnsEffect)];
    [UIView setAnimationDelegate:self];


    self.view_image.transform = CGAffineTransformScale(self.view_image.transform, 1.06, 1.06);
    self.view_image.center = CGPointMake(self.frame.size.width/1.7, self.frame.size.height/2);

    [UIView commitAnimations];
}

- (void)endKenBurnsEffect {

    [UIView beginAnimations:@"b" context:self.view_image];
    [UIView setAnimationCurve:UIViewAnimationCurveLinear];
    [UIView setAnimationDuration:5];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDidStopSelector:@selector(beginKenBurnsEffect)];
    [UIView setAnimationDelegate:self];

    self.view_image.transform = self.origTransform;
    self.view_image.center = self.origPoint;

    [UIView commitAnimations];
}

初始化 UIImageView 后,我将当前的 Transform 和 Center 值保存到一个属性中。

self.origTransform = self.view_image.transform;
self.origPoint = self.view_image.center;

我也试过只用一个动画和setAnimationAutoReverse,但是在动画完成后,它在没有动画的情况下放大(在它做了缩小后缓慢动画)。

也许您知道问题可能出在哪里。

提前谢谢你:)

【问题讨论】:

    标签: iphone objective-c animation


    【解决方案1】:

    您是否尝试过使用一个 CAAnimationGroup 和几个 CAAnimation?

    NSMutableArray * animations = [ NSMutableArray array ] ;
    {
        CAAnimation * anim = [ CABasicAnimation animationWithKeyPath:@"transform" ] ;
        anim.fromValue = [ NSValue valueWithCGAffineTransform:CGAffineTransformScale(...) ] ;
        [ array addObject:anim ] ;
    }
    {
        CAAnimation * anim = // make intro position transform
        [ array addObject:anim ] ;
    }
    
    {
        CAAnimation * anim = // make outro position transform for layer.transform
        anim.offset = 5.0;
    }
    
    {
        CAAnimation * anim = // make outro position transform for layer.position
        anim.offset = 5.0;
    }
    
    CAAnimationGroup * group = [ CAAnimationGroup animation ] ;
    group.animations = animations ;
    
    [ CATransaction begin ] ;
    [ self.view.layer addAnimation:group forKey:nil ] ;
    [ CATransaction commit ] ;
    

    ...这只是一个草稿

    【讨论】:

      【解决方案2】:

      如果从主线程调用 endKenBurnsEffect 会发生什么?

      即将 [UIView setAnimationDidStopSelector:@selector(endKenBurnsEffect)]; 更改为 `[UIView setAnimationDidStopSelector:@selector(invokeEndKenBurnsEffect)];'

      -(void)invokeEndKenBurnsEffect 的样子:

      -(void)invokeEndKenBurnsEffect
      {
          [ self performSelectorOnMainThread:@selector( endKenBurnsEffect )
                                  withObject:nil 
                               waitUntilDone:NO ] ;
      }
      

      【讨论】:

      • 感谢您的回答。但这似乎并不能解决问题。如果我将 setAnimationBeginsFromCurrentState-line 注释掉,有时效果会起作用。但这不确定,如果我重新启动应用程序,它有时会表现得很奇怪。下一个问题是,我必须以某种方式停止动画,但我看不到效果可靠的解决方案。你可能有其他想法吗?
      【解决方案3】:

      你仍然可以使用基于块的递归动画:

      在您的 .h 文件中

      @interface YourClass : UIViewController{
          BOOL kenBurnsIsAnimating;
      }
      

      在您的 .m 文件中

      - (void)viewDidLoad{
         kenBurnsIsAnimating = YES;  
         [self kenBurns:YES];  
      }
      
      - (void)kenBurns:(BOOL)isOpening{
          if (kenBurnsIsAnimating) {
              [UIView animateWithDuration:5.0
                                    delay:1.0
                                  options:UIViewAnimationCurveEaseInOut
                               animations:^{
                                   if (isOpening) {
                                       // do your opening animation (zoom in and panning)
                                   }else{
                                       // do your closing animation (zoom out and panning)
                                   }
                               }
                               completion:^(BOOL finished){
                                   if (finished) {
                                       [self kenBurns:!isOpening];
                                   }
                               }];
          }    
      }
      

      这样您将使用递归创建过渡,并且您将在动画块中执行的任何操作都会一遍又一遍地发生(这就是为什么存在 isOpening YES/NO 值),直到您不会将 kenBurnsIsAnimating 设置为 NO。但是,当前的动画必须完成。

      有关基于块的动画的更多信息,请查看http://developer.apple.com/library/IOS/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/AnimatingViews/AnimatingViews.html#//apple_ref/doc/uid/TP40009503-CH6-SW4 还有一个示例用于连接两个基于块的动画。清单 4-2。

      【讨论】:

        猜你喜欢
        • 2012-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-30
        相关资源
        最近更新 更多