2012-08-22 15 views
0

好吧,我的代碼有問題。我想使用imageViewers製作某種類似網格的網格,但是當更改imageViewers的圖像方法時,它只會在屏幕/圖像查看器完成執行後更新屏幕,而不是在執行屏幕/圖像查看器時執行。我有一個無限循環的方法,它會在您按下按鈕時更改imageViewers的圖片。這些按鈕調用將布爾變量更改爲true的方法,因此主遊戲循環通過不斷檢查某些變量是否爲真來知道被按下的是什麼。但是因爲遊戲循環永遠不會結束,屏幕永遠不會更新。有沒有辦法在執行過程中更新屏幕上的內容?UIImageViewer不更新其內容,直到方法完成,而不是執行命令

我使用此代碼來改變imageViewers內容:

 UIImage * white = [UIImage imageNamed: @"White.png"]; 
    UIImage * blue = [UIImage imageNamed: @"Blue.png"]; 
    int tagInt=1; 
    for (int y = 0;y<10;y++){ 
     for (int x = 0;x<10;x++){ 
      UIImageView *imageView; 
      imageView = [[UIImageView alloc] initWithImage:white];     imageView.frame =CGRectMake(x*32,y*37,32,37); 
      imageView.image = white; 
      imageView.tag=tagInt; 
      [self.view addSubview:imageView]; 
      tagInt++; 
     } 
    } 
    for (int u = 1;u<20;u++){ 
     [NSThread sleepForTimeInterval:(1)]; 
     UIImageView *g = (UIImageView*)[self.view viewWithTag:u]; 
     g.image =blue; 
    } 

這是一個人爲的例子,因爲我的實際代碼太長,但有同樣的問題。它只在最後一個for循環(此延遲/線程休眠命令)完成後在屏幕上更新,而不是執行代碼行。

編輯:這裏是你想要的任何方面的項目:https://www.dropbox.com/s/cvefllnhgj0tp6g/Stacker.zip

+0

爲什麼你就不能檢查您的按鈕的方法哪些變量是真實的並在按鈕方法中相應地更改圖像視圖 –

+0

好主意,我想這會更有意義。儘管即使沒有按鈕被按下,圖像視圖仍然在變化。所以這一點不會解決我的問題。但如果我的遊戲性質不同:)。 –

回答

3

在iOS系統中,所有的UI相關的東西在主(UI)線程中完成的。如果您有阻止ui線程的操作 - 這意味着它會像您一樣忙線程 - 不會發生視圖更新。 所以你必須這樣改變你的代碼,你有一個「updateView」方法來改變圖像視圖的內容。這種方法必須定期調用,例如,通過使用一個NSTimer實例:https://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/nstimer_Class/Reference/NSTimer.html

假設,代碼更新您的視圖被命名爲「更新視圖」,可以定義這樣的計時器:

NSTimer *timer; 
    timer = [NSTimer scheduledTimerWithTimeInterval: 1 
         target: self 
         selector:@selector(updateView:) 
         userInfo: nil 
         repeats: YES]; 

那麼計時器會打電話給你的UpdateView方法每一秒並且不會阻止主線程再次允許您對視圖所做的更改顯示。

+0

好的,謝謝。這是合乎邏輯的。我唯一的問題是: 1)一旦聲明瞭NSTimer,它是否每隔一段時間都執行選擇器中指定的方法? 2)你會在哪裏聲明這個NSTimer?我是否必須在主UI方法中執行此操作?我甚至不知道它在哪裏,或者我只是將它聲明爲相應ViewController中的全局變量? –

+0

你可以聲明它,例如它的viewDidLoad方法。它將在定義後立即開始觸發定義的方法 - 因此不需要進一步調用即可啓動它。嚴格地說,你不需要在成員變量中保存對它的引用,但是當你想停止它或者你不需要它的時候,這樣做會很好,並且調用'[timer invalidate]'了。 –

+0

謝謝。你給出的代碼行「[timer invalidate]」只能在聲明它的方法中工作。但顯然,它只是在開始時執行viewDidLoad方法。如何以不同的方式結束計時器/使這種方式工作? –

1

我認爲CA動畫會做你需要的。嘗試這樣的:

#import <QuartzCore/QuartzCore.h> 

- (void)imageView:(UIImageView *)imageView crossfadeTo:(UIImage *)image duration:(NSTimeInterval)duration { 

    [imageView.layer removeAnimationForKey:@"animateContents"]; 

    CABasicAnimation *crossFade = [CABasicAnimation animationWithKeyPath:@"contents"]; 
    crossFade.duration = duration; 
    crossFade.fromValue = (id)imageView.image.CGImage; 
    crossFade.toValue = (id)image.CGImage; 
    [imageView.layer addAnimation:crossFade forKey:@"animateContents"]; 

    imageView.image = image; 
} 

這也可以在UIImageView上做成一個類別方法。這樣稱呼它:

UIImage *white = [UIImage imageNamed: @"White.png"]; 
UIImage *blue = [UIImage imageNamed: @"Blue.png"]; 

UIImageView *imageView = [[UIImageView alloc] initWithImage:white]; 
[self imageView:imageView crossfadeTo:blue duration:5.0]; 

或者,這可以用塊動畫來完成調用同樣的方式,具體如下:

- (void)imageView:(UIImageView *)imageView crossfadeTo:(UIImage *)image duration:(NSTimeInterval)duration { 

    UIImageView *fadeToImageView = [[UIImageView alloc] initWithFrame:imageViewFrame]; 
    fadeToImageView.image = image; 
    [imageView.superview insertSubview:fadeToImageView belowSubview:imageView]; 

    [UIView animateWithDuration:duration animations:^{ 
     imageView.alpha = 0.0; 
    } completion:^(BOOL finished) { 
     imageView.image = image; 
     imageView.alpha = 1.0; 
     [fadeToImageView removeFromSuperview]; 
    }]; 
} 
+0

謝謝。我用Steffen Blass的答案,因爲它對我來說更有意義/我先讀它。你看起來更高級,但我不認爲我真的需要它。使用你的方法有什麼好處? –

+0

當然。感謝您的評論。動畫是逐漸改變視圖屬性的方法。你可能會發現你需要一次做幾十個,一些開始於其他人結束之後,等等。查看動畫 - 特別是底部的塊方法 - 可以讓你完成工作,而不會失去你的想法跟蹤定時器並保持更新方法中的正確狀態。只是爲了好玩,粘貼第二種方法,我建議並運行它。我向你保證,你最終會使用塊動畫並丟掉大部分定時器。 – danh

+0

再次感謝。我將它複製/粘貼到我的代碼中,但不知道如何正確整合它。如果你關心我的項目,我已經在OP中的代碼中添加了一個Dropbox鏈接。請注意,這是我可能真正想要使用的第一個項目,所以不要指望任何花哨的東西:P。 –

相關問題