2015-08-14 81 views
2

我想獲得一個UIView擴展使用動畫塊,它完美的作品。但是,我想要一個UILabel從0開始,每0.01秒添加1直到它達到100. 我在動畫完成後創建了一個線程,它可以工作,但它會導致我設置的動畫無法執行任何操作。 我已經嘗試了許多不同的東西,但沒有運氣。什麼是實現這一目標的最佳方式?UIView動畫同時計數線程

我有相同的結果,所有的人簡單的嘗試:

[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]; 
    }); 
    } 
} 

回答

1

這裏有兩個問題:

  1. 關於幀的動畫,同時改變標籤,問題是改變標籤的文本會導致重新應用約束。正確的解決方案是不通過更改框架來設置動畫,而是通過更改指定框架的約束,然後在動畫塊中調用layoutIfNeeded。見Animating an image view to slide upwards

  2. 關於標籤的動畫:

    • 你有沒有保證更新可以快速處理這一點。 (事實上​​,你應該計劃永遠不會實現超過60 fps)。

    • 即使你能夠充分減少更新的頻率,你永遠不會相信他們會以恆定的速度處理(某些東西否則總是會阻塞主線程幾毫秒,導致數字的遞增不一致)。

    所以,你應該使用一個計時器(或更好「顯示鏈接」,這就好比一個計時器,但協作當屏幕隨時可以刷新被稱爲),計算所經過的時間(這樣計數器就不會受到其他事情的影響,但數值會從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]; 
}]; 
+0

非常感謝你的幫助我現在正在使用這種方法。我注意到,我試圖更新的視圖將與標籤計數同時移動,但尺寸不會改變。當它移動時,它從它將要結束的位置開始並移動到原來的位置。 當我刪除/註釋標籤計數器的代碼它工作正常:它調整大小和更改設置的位置。 任何想法爲什麼標籤計數器存在會導致動畫像這樣執行? 你的回答非常有幫助,但不幸解決了這個問題。 – JeremyF

+0

其實我找到了問題,它不能正常工作。不過謝謝你,因爲你的代碼是非常重要的,我相應地更新了我的代碼。 – JeremyF

+1

@JeremyF - 是的,問題在於,除了使用顯示鏈接更改標籤之外,另一個問題是更改文本將導致重新應用約束(中斷動畫)。當您在自動佈局中爲視圖設置動畫時,不應直接更改「框架」,而應更改約束並調用「layoutIfNeeded」。看修改後的答案。 – Rob

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]; 
    }); 
} 
} 
0

我終於明白了。我以前應該看到過。

首先我想這是一個約束的問題,所以我從我更新的UIView中刪除約束。這是必要的,但沒有解決問題。

整個視圖控制器仍然有其自己的約束,我不能刪除這些,因爲它們是需要的。所以我所做的是添加了一個帶約束的新UIView,並將UIView放在這個新的UIView上。

這解決了問題,因爲動畫UIView不再負責任何約束或負責受任何其他約束的影響。

我仍然不明白的是如何更新UILabel同時導致動畫在涉及約束時失敗,但在刪除UILabel代碼時工作得很好。但是,這確實解決了這個問題。