【问题标题】:UIView Animation with Simultaneous Counting ThreadUIView 动画与同时计数线程
【发布时间】:2015-08-14 03:20:56
【问题描述】:

我正在尝试使用动画块来扩展 UIView,效果很好。但是,我希望 UILabel 从 0 开始,每 0.01 秒加 1,直到达到 100。 我在动画之后创建了一个线程来完成此操作,它可以工作,但它会导致我设置的动画什么都不做。 我尝试了很多不同的事情,但没有运气。实现这一目标的最佳方法是什么?

我最简单的尝试与所有其他的结果相同:

[UIView animateWithDuration:1 animations:^{
    _lView.frame = CGRectMake(_lView.frame.origin.x,_lView.frame.origin.y+_lView.frame.size.height,_lView.frame.size.width,-500);
}];

[[[NSThread alloc]initWithTarget:self selector:@selector(startcounting) object:nil]start];


-(void)startcounting{
for(int x=0; x<100; x++){
    [NSThread sleepForTimeInterval:0.01];
    ++_mcount;
    dispatch_async(dispatch_get_main_queue(), ^{
        _cLabel.text = [NSString stringWithFormat:@"%i",_mcount];
    });
  }
}

【问题讨论】:

    标签: ios objective-c multithreading animation uiview


    【解决方案1】:

    有两个问题:

    1. 关于框架的动画同时更改标签,问题是更改标签的文本会导致重新应用约束。正确的解决方案是不通过更改帧来制作动画,而是通过更改指示帧的约束,然后在动画块中调用layoutIfNeeded。见Animating an image view to slide upwards

    2. 关于标签的动画:

      • 您无法保证可以如此快速地处理更新。 (事实上​​,你应该计划永远不要超过 60 fps。)

      • 1234563数字的增量不一致)。
    3. 因此,您应该改用计时器(或者更好的“显示链接”,它类似于计时器,但在屏幕准备好刷新时协调调用),计算经过的时间(这样计数器不会受到正在发生的其他事情的影响,但该值会很快从 0 变为 100,从而产生您正在寻找的效果),并相应地更新标签。例如:

      @interface ViewController ()
      
      @property (nonatomic, strong) CADisplayLink *displayLink;
      @property (nonatomic) CFTimeInterval startTime;
      
      @property (weak, nonatomic) IBOutlet UILabel *label;
      
      @end
      
      @implementation ViewController
      
      - (void)startDisplayLink {
          self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
          self.startTime = CACurrentMediaTime();
          [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
      }
      
      - (void)stopDisplayLink {
          [self.displayLink invalidate];
          self.displayLink = nil;
      }
      
      - (void)handleDisplayLink:(CADisplayLink *)displayLink {
          CFTimeInterval elapsed = CACurrentMediaTime() - self.startTime;
      
          if (elapsed < 1) {
              self.label.text = [NSString stringWithFormat:@"%.0f", elapsed * 100.0];
          } else {
              self.label.text = @"100";
              [self stopDisplayLink];
          }
      }
      

    因此,结合这两点,只需调整约束(在将出口添加到约束之后)并调用startDisplayLink(从主线程),您的标签将在一秒钟内从 0 更新到 100作为视图动画:

    [self startDisplayLink];
    self.topConstraint.constant += self.lView.frame.size.height;
    [UIView animateWithDuration:1.0 animations:^{
        [self.view layoutIfNeeded];
    }];
    

    【讨论】:

    • 非常感谢您的帮助,我现在正在使用这种方法。我注意到我试图更新的视图将与标签计数同时移动,但它的大小不会改变。当它移动时,它从将要结束的位置开始,然后移动到原来的位置。当我删除/注释标签计数器的代码时,它工作正常:它调整大小并更改设置的位置。知道为什么标签计数器的存在会导致动画像这样执行吗?您的回答非常有帮助,但不幸的是并没有解决问题。
    • 其实我发现了问题,但它不能正常工作。不过谢谢你,因为你的代码非常重要,我已经相应地更新了我的代码。
    • @JeremyF - 是的,问题在于除了更改带有显示链接的标签外,另一个问题是更改文本将导致重新应用约束(中断动画)。在自动布局中为视图设置动画时,不应直接更改frame,而应更改约束并调用layoutIfNeeded。请参阅修改后的答案。
    【解决方案2】:
    _lView.frame = CGRectMake(_lView.frame.origin.x,[[UIScreen mainScreen] bounds].size.height,_lView.frame.size.width,_lView.frame.size.height);    
    [[[NSThread alloc]initWithTarget:self selector:@selector(startcounting) object:nil]start];
    
    
    /*
    Comment this code
    
    [UIView animateWithDuration:1 animations:^{
    _lView.frame = CGRectMake(_lView.frame.origin.x,_lView.frame.origin.y+_lView.frame.size.height,_lView.frame.size.width,-500);
    }];
    */
    

    修改这个方法

    -(void)startcounting{
    int initialY = _lView.frame.origin.y;
    for(int x=0; x<=100; x++){
        [NSThread sleepForTimeInterval:0.01];
        dispatch_async(dispatch_get_main_queue(), ^{
            if (initialY>=_lView.frame.origin.y-(x*0.03))//adjust 0.03 as you required
            {
                _lView.frame = CGRectMake(_lView.frame.origin.x,_lView.frame.origin.y-(x*0.03),_lView.frame.size.width,_lView.frame.size.height);//adjust 0.03 as you required
            }
            else
            {
                _lView.frame = CGRectMake(_lView.frame.origin.x,initialY,_lView.frame.size.width,_lView.frame.size.height);
            }
           _cLabel.text = [NSString stringWithFormat:@"%i",x];
        });
    }
    }
    

    【讨论】:

      【解决方案3】:

      我终于明白了。我应该以前看过这个。

      首先,我认为这是约束的问题,因此我从正在更新的 UIView 中删除了约束。这是必要的,但没有解决问题。

      整个视图控制器仍然有自己的约束,我无法根据需要删除它们。所以我所做的是添加一个带有约束的新 UIView,并将 UIView 放在这个新 UIView 上进行动画处理。

      这解决了问题,因为动画 UIView 不再负责任何约束或负责受任何其他约束的影响。

      我仍然不明白的是如何同时更新 UILabel 会导致动画在涉及约束时失败,但在删除 UILabel 代码时工作得很好。但是,尽管这确实解决了问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多