【问题标题】:How to animate a floating UIView in ObjectiveC如何在 Objective C 中为浮动 UIView 设置动画
【发布时间】:2014-09-10 11:02:36
【问题描述】:

我正在尝试将UIView 动画化为浮动对象或气球:D UIView 在屏幕中间,我希望它在第一个启动点周围随机浮动。不跨越屏幕或类似的东西,只是漂浮在它周围 5 个像素的区域内。

有什么建议吗? :D

我试过这个:

[UIView animateWithDuration:0.1
                      delay:0.0
                    options: UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse | UIViewAnimationOptionAllowUserInteraction
                 animations:^{
                     myCircleUIView.transform = CGAffineTransformMakeTranslation([self randomFloatingGenerator], [self randomFloatingGenerator]);
                 }
                 completion:NULL];

randomFloatingGenerator 生成一个介于 -5 和 5 之间的数字。问题是,它只执行一次,并且不断重复使用相同的随机值。

EDIT1: 现在我已经尝试过了

-(void)animationLoop{

[UIView animateWithDuration:1.0
                     animations: ^{ myCircleUIView.transform = CGAffineTransformMakeTranslation([self randomFloatingGenerator], [self randomFloatingGenerator]); }
                     completion:
     ^(BOOL finished) {
         [UIView animateWithDuration:1.0
                          animations:^{ myCircleUIView.transform = CGAffineTransformMakeTranslation(0,0);
                          }
                          completion:
          ^(BOOL finished) {[self animationLoop];}];
     }];

但它仍然无法正常工作,动画......糟糕......我想我正在犯一些愚蠢的错误,我需要第二双眼睛来帮助我。

EDIT2: 修好了。

 -(void)animationLoop{
    CGPoint oldPoint = CGPointMake(myCircleUIView.frame.origin.x, myCircleUIView.frame.origin.y);
    [UIView animateWithDuration:1.0
                     animations: ^{ myCircleUIView.frame = CGRectMake(myCircleUIView.frame.origin.x + [self randomFloatingGenerator], myCircleUIView.frame.origin.y + [self randomFloatingGenerator], myCircleUIView.frame.size.width, myCircleUIView.frame.size.height); }
                     completion:
     ^(BOOL finished) {
         [UIView animateWithDuration:1.0
                          animations:^{ myCircleUIView.frame = CGRectMake(oldPoint.x, oldPoint.y, myCircleUIView.frame.size.width, myCircleUIView.frame.size.height);}
                          completion:
          ^(BOOL finished) {[self animationLoop];}];
     }];
}

感谢任何人的帮助。

编辑 3:

有人发布了增强的代码。

【问题讨论】:

  • 使用 NSTimer 并在其中调用上面的代码...

标签: ios objective-c animation uiview


【解决方案1】:

@Shamy 的解决方案,经过改进、修复和 CPU 安全。

-(void)animateFloatView:(UIView*)view{

    // Abort the recursive loop
    if (!view)
        return;

    CGPoint oldPoint = CGPointMake(view.frame.origin.x, view.frame.origin.y);
    [UIView animateWithDuration:0.6
                     animations: ^{ view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y - 15, view.frame.size.width, view.frame.size.height); }
                     completion:
     ^(BOOL finished) {

         if (finished) {
             [UIView animateWithDuration:0.6
                              animations:^{ view.frame = CGRectMake(oldPoint.x, oldPoint.y, view.frame.size.width, view.frame.size.height);}
                              completion:
              ^(BOOL finished2) {
                  if(finished2)
                      [self animateFloatView:view];
              }];

         }
     }];
}

当你想停止动画时(离开 View Controller 时需要),使用 nil 调用函数,如下所示:

    [self recursiveFloatingAnimation:nil];

不停止动画会导致递归循环无限运行,压垮CPU栈。

【讨论】:

    【解决方案2】:

    斯威夫特 4

    UIView.animate(withDuration: 0.6, delay: 0.1, options: [.autoreverse, .repeat], animations: {
        self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y - 15, width: self.frame.size.width, height: self.frame.size.height)
    },completion: nil )
    

    【讨论】:

    • 如果您在 X 和 Y 中使用两个介于 -15 和 15 之间的随机变量来制作 Delta,它将非常适合我尝试做的事情。
    【解决方案3】:

    它将以这种方式运行。当您重复动画而不是功能时。因此,每次您在第一次调用时设置时,它都会重复相同的动画。这样做:

    @interface AAViewController ()
    
    @property (nonatomic, strong) UIView * floatingView;
    @end
    
    @implementation AAViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        _floatingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
        [_floatingView setBackgroundColor:[UIColor redColor]];
        [self.view addSubview:_floatingView];
    
        [self circleUIViewFloating];
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    #pragma mark - Circle UIView floating
    
    - (void) circleUIViewFloating {
    
        [UIView animateWithDuration:2.0
                         animations:^{
                             _floatingView.transform = CGAffineTransformMakeTranslation([self randomFloatingGenerator : 270], [self randomFloatingGenerator:480]);
                         } completion:^(BOOL finished) {
                             [self circleUIViewFloating];
                         }];
    }
    
    - (int) randomFloatingGenerator : (int) max{
        return arc4random() % max;
    }
    

    这里是complete running project

    【讨论】:

    • 这样做的问题是它翻译了对象,所以当它完成时,它的位置不是它开始的位置,而是它翻译到的位置。我不想翻译对象,我只想为它设置动画。如果我使用重新动画,它会继续跳跃,如果我不使用它,它会继续自行漂浮,而不是像我试图做的那样围绕其原始坐标。
    • 我不确定 UIkit 是否适合您的任务。如果您想编写游戏代码,请查看 spriteKit、Cocos2d 或类似产品!
    • 否则看时序曲线。使用easeInEaseOut 避免突然移动。
    • 问题似乎是,它只是从我希望它动画的位置开始动画,而不是从,但不明白为什么......
    【解决方案4】:

    您可以使用CABasicAnimation 实现悬停或浮动效果。

    您必须包含QuartzCore 框架才能使用它。

    Swift 4.2:

    import QuartzCore
    
    let hover = CABasicAnimation(keyPath: "position")
        hover.isAdditive = true
        hover.fromValue = NSValue(cgPoint: CGPoint.zero)
        hover.toValue = NSValue(cgPoint: CGPoint(x: 0.0, y: -5.0))
        hover.autoreverses = true
        hover.duration = 0.8
        hover.repeatCount = Float.infinity
        myCustomView.layer.add(hover, forKey: "hoverAnimation")
    

    确保在不再显示视图时移除动画。

        override func viewWillDisappear(_ animated: Bool) {
            // Stop animating when view is going to disappear
            myCustomView.layer.removeAllAnimations()
        }
    

    【讨论】:

      【解决方案5】:
      -(void)animationLoop{
      CGPoint oldPoint = CGPointMake(myCircleUIView.frame.origin.x, myCircleUIView.frame.origin.y);
      [UIView animateWithDuration:1.0
                       animations: ^{ myCircleUIView.frame = CGRectMake(myCircleUIView.frame.origin.x + [self randomFloatingGenerator], myCircleUIView.frame.origin.y + [self randomFloatingGenerator], myCircleUIView.frame.size.width, myCircleUIView.frame.size.height); }
                       completion:
       ^(BOOL finished) {
           [UIView animateWithDuration:1.0
                            animations:^{ myCircleUIView.frame = CGRectMake(oldPoint.x, oldPoint.y, myCircleUIView.frame.size.width, myCircleUIView.frame.size.height);}
                            completion:
            ^(BOOL finished) {[self animationLoop];}];
       }];
      }
      

      【讨论】:

      • 这个递归解决方案阻塞了主线程。我强烈反对使用此解决方案,除非您在离开 VC 之前将其停止。此外,您需要在再次调用之前检查当前动画是否准备就绪,否则您将进入无限循环。
      • 是的,我在想这个,那么你将如何停止和启动动画?使用 UIViewPropertyAnimator?
      【解决方案6】:

      Swift 2.1 版本在这里:

      func animateFloatView(view: UIView?) {
          // Abort the recursive loop
          guard let view = view else { return }
      
      
          let oldPoint: CGPoint = CGPointMake(view.frame.origin.x, view.frame.origin.y)
          UIView.animateWithDuration(0.6, animations: {() -> Void in
              view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y - 15, view.frame.size.width, view.frame.size.height)
              }, completion: {(finished: Bool) -> Void in
                  if finished {
                      UIView.animateWithDuration(0.6, animations: {() -> Void in
                          view.frame = CGRectMake(oldPoint.x, oldPoint.y, view.frame.size.width, view.frame.size.height)
                          }, completion: {(finished2: Bool) -> Void in
                              if finished2 {
                                  self.animateFloatView(view)
                              }
                      })
                  }
          })
      }
      

      【讨论】:

        【解决方案7】:

        Swift 3.1:

        func animateFloatView(_ view: UIView?) {
            guard let view = view else { return }
            let oldYCoordinate = view.center.y
        
            UIView.animate(withDuration: 0.6, animations: {
                view.center.y -= 15
            }, completion: { _ in
                UIView.animate(withDuration: 0.6, animations: {
                    view.center.y = oldYCoordinate
                }, completion: { _ in
                    self.animateFloatView(view)
                })
            })
        }
        

        【讨论】:

        • 你如何打破这个动画,比如阻止它浮动?
        猜你喜欢
        • 2016-10-14
        • 2014-08-31
        • 2017-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-03
        • 1970-01-01
        相关资源
        最近更新 更多