我正在尝试使用动画块来扩展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];
});
}
}
答案 0 :(得分:1)
有两个问题:
关于同时更改标签的帧动画,问题是更改标签的文本会导致重新应用约束。正确的解决方案是不通过更改帧来设置动画,而是通过更改指示帧的约束然后在动画块中调用layoutIfNeeded
来设置动画。请参阅Animating an image view to slide upwards
关于标签的动画:
您无法保证可以快速处理更新。 (事实上,你应该计划永远不要超过60 fps。)
即使您能够充分降低更新频率,也永远无法保证它们能够以恒定速率处理(其他东西总能阻止主线程几毫秒,产生不一致的数字递增)。
所以,你应该使用一个计时器(或更好的&#34;显示链接&#34;,它就像一个计时器,但在屏幕准备好刷新时协调调用),计算经过的时间(这样,计数器不会受到正在发生的其他事情的影响,但是这个值会从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];
}];
答案 1 :(得分:0)
_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];
});
}
}
答案 2 :(得分:0)
我终于明白了。我以前应该看过这个。
首先我认为这是约束的问题所以我从UIView中删除了我正在更新的约束。这是必要的,但没有解决问题。
整个视图控制器仍然有自己的约束,我无法在需要时删除它们。所以我所做的是添加了一个带有约束的新UIView,并将UIView设置为在这个新的UIView上动画。
这解决了这个问题,因为动画UIView不再对任何约束负责,也不负责受任何其他约束的影响。
我还不明白的是,当涉及约束时,如何同时更新UILabel会导致动画失败,但是当删除UILabel代码时,工作完全正常。然而,这确实解决了这个问题。