我对一些我只是为了好玩而尝试的东西感到有些困惑。我编写了一个名为animateBars_V1
的小方法,该方法使用UIImageViews数组并改变每个UIImageView的高度,以显示一组不断变化的彩色条。
- (void)animateBars_V1 {
srandom(time(NULL));
for(UIImageView *eachImageView in [self barArray]) {
NSUInteger randomAmount = kBarHeightDefault + (random() % 100);
CGRect newRect;
CGRect barRect = [eachImageView frame];
newRect.size.height = randomAmount;
newRect.size.width = barRect.size.width;
newRect.origin.x = barRect.origin.x;
newRect.origin.y = barRect.origin.y - (randomAmount - barRect.size.height);
[eachImageView setFrame:newRect];
}
}
这很好用,然后在按下按钮时添加了带UIAction的UIButton。每次按下按钮时,都会调用animateBars_V1
并更新彩色条。
- (IBAction)buttonPressed {
for(int counter = 0; counter<5; counter++) {
[self animateBars_V1];
NSLog(@"COUNTER: %d", counter);
}
}
我的问题只是为了好玩我决定每按一次按钮,我会拨打animateBars_V1
5次。发生的事情是,直到循环退出后,条形才会改变。这导致:
Screen as per storyboard
COUNTER: 0
COUNTER: 1
COUNTER: 2
COUNTER: 3
COUNTER: 4
Screen Updates
这是正确的行为吗?我不需要修复或解决方法,因为这只是为了好玩,我更好奇将来发生的事情。
答案 0 :(得分:4)
如果你在一个循环中多次调用animateBars_V1
,那么条形的框架会被多次设置,但在它们被渲染之前,animateBars_V1
会再次被调用,并且框架被设置到一个新的位置/大小。
对渲染(drawRect:
和相关方法)的调用直到循环结束后才会发生 - 因为它是一个IBAction,它必须在主线程中调用,这意味着所有渲染都是阻止,直到代码完成。
当然有几种解决方案。执行多动画操作的一种简单方法是以下列方式使用UIView animateWithDuration:animations:completion:
:
- (IBAction)buttonPressed {
[self animateBarsWithCount:5];
}
- (void)animateBarsWithCount:(int)count
{
[UIView animateWithDuration:.25f animations:^{
[self animateBars_V1];
}completion:^(BOOL finished){
[self animateBarsWithCount:count - 1];
}];
}
//animateBars_V1 not repeated
当然,如果您只想一次运行动画,(但实际上是动画的),您应该这样做:
- (IBAction)buttonPressed {
[UIView animateWithDuration:.25f animations:^{
[self animateBars_V1];
} completion:nil];
}
答案 1 :(得分:2)
CrimsonDiego是对的
您可以尝试延迟每次通话:
- (IBAction)buttonPressed {
for(int counter = 0; counter<5; counter++) {
float ii = 1.0 * counter / 10;
[self performSelector:@selector(animateBars_V1) withObject:nil afterDelay:ii];
// [self animateBars_V1];
NSLog(@"COUNTER: %d", counter);
}
}
答案 2 :(得分:0)
问题出在这里
for(int counter = 0; counter<5; counter++) {
[self animateBars_V1];
NSLog(@"COUNTER: %d", counter);
}
这个for循环在纳秒内执行,你的眼睛无法赶上那个变化,因为眼睛只能检测到1/16秒。
用于测试可以在运行五次的计时器中运行此代码的内容。
<强>被修改强> 删除了睡眠呼叫,因为它将睡眠主线程,一切都将停止。所以在这里使用Timer