2014-03-31 21 views
0

我試圖更新我的Android應用程序中幾個TextView s的背景顏色。我想在這兩者之間設置每種顏色有短暫的停頓,即:在Android應用程序中更新短暫的睡眠背景顏色

<set TextView one's background to gold> 
<pause 500ms> 
<set TextView two's background to gold> 
<pause 500ms> 
<set TextView three's background to gold> 
<pause 500ms> 

的目標是使某種跨箱進步高亮模式。

我遇到的問題是所有的盒子在暫停後立即更新。我已經read that如果我想強制視圖繪製自己,我需要撥打invalidate(),我已經嘗試過,但它似乎沒有做任何事情。我不確定是否我使用的睡眠方法導致了問題,或者如果我沒有用正確的方法強制繪製更新。希望有人能指出我朝着正確的方向:

Resources res = getResources(); 
    for(int i=0; i<3; i++){ 
     int id = res.getIdentifier("txt"+Integer.toString(box[i]), "id", 
            getApplicationContext().getPackageName()); 
     TextView temp = (TextView)findViewById(id); 

     // Set gold with 50% opacity 
     temp.setBackgroundColor(Color.parseColor("#ffd700")); 
     temp.getBackground().setAlpha(127); 

     // Force redraw 
     temp.invalidate(); 

     // Sleep for half a second 
     try { 
      Thread.sleep(500); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

注:我阻塞,直到背景的這個序列中的主要線索更改被更新,沒有什麼應該發生,直到這三個TextView■找了更新,這就是爲什麼我從主UI線程調用sleep()


編輯
我試圖用一個可運行的,而「堵」我的主線程做背景的更新。如果這是應該說不定處理方式有人能指出我我要去哪裏錯了:

boolean moveon; 
    //... 
    onCreate() { 
     moveon = false; 
    //... 

    Handler myh = new Handler(); 
    Runnable myr = new Runnable() { 
     public void run() { 
      Resources res = getResources(); 
      for(int i=0; i<3; i++){ 
       id = res.getIdentifier("txt"+Integer.toString(winners[i]), "id", 
         getApplicationContext().getPackageName());  
       TextView temp = (TextView)findViewById(id); 
       temp.setBackgroundColor(Color.parseColor("#ffd700")); 
       temp.getBackground().setAlpha(127); 
       temp.invalidate(); 
      } 
      moveon = true; 
     } 
    }; 
    myh.post(myr); 
    while(moveon == false){} //blocks forever here, perhaps the update to from the 
           // runable doesn't propagate? 
+2

「我希望主線程被阻止」 - 不,您希望在此期間禁用UI,而不是阻止,這就是爲什麼它們都是同時發生的原因。一個更好的選擇是全局布爾值,我們稱它爲「啓用」,並在操作期間將其設置爲false,然後在更新完成時將其設置爲true,同時從輔助線程調用postInvalidate()。然後在你的UI線程中,你應該檢查在允許任何額外的操作發生之前是否啓用等於真。這會造成被封鎖的幻覺,而不會被封鎖。 – Guardanis

+0

@Guardanis - 將主UI線程放入一個無限的'while'循環中,等待全局更新,而不是讓它進入睡眠狀態? 「阻塞」,「禁用」,「停滯」......無論如何,只有在我需要的更新完成之後,它纔會移動。我看到,同樣的事情,我不明白爲什麼'invalidate()'不會導致UI的更新。我錯了嗎? – Mike

+0

它實際上是更新UI,但onDraw(Canvas)調用在調用invalidate()後不會立即發生。系統會對它進行排隊,這似乎是在所有睡眠完成後發生的,因爲UI線程被睡眠呼叫阻塞。如果您檢查文檔無效,您應該注意以下行:「將在未來的某個時刻被調用。」 – Guardanis

回答

2

要帶我提出的意見,並張貼在這裏以及:

「我希望主線程阻塞」 - 不,你想要的UI禁用 期間,不被阻止,這就是爲什麼它們都發生在 一次。更好的選項是全局布爾值,我們稱之爲「啓用」 ,並在操作過程中將其設置爲false,然後在更新完成時將其設置爲真 ,同時從 調用postInvalidate()從屬線程。然後在你的UI線程中,你應該檢查看看 ,如果在允許任何附加操作 發生之前啓用等於真。這將創建的被封鎖的幻想,而不 它實際上被阻止

現在,把你的代碼:

boolean moveon; 
//... 
onCreate() { 
    moveon = false; 
//... 

Handler myh = new Handler(); 
Runnable myr = new Runnable() { 
    public void run() { 
     Resources res = getResources(); 
     for(int i=0; i<3; i++){ 
      id = res.getIdentifier("txt"+Integer.toString(winners[i]), "id", 
        getApplicationContext().getPackageName());  
      TextView temp = (TextView)findViewById(id); 
      temp.setBackgroundColor(Color.parseColor("#ffd700")); 
      temp.getBackground().setAlpha(127); 
      temp.invalidate(); 
     } 
     moveon = true; 
    } 
}; 
myh.post(myr); 
while(moveon == false){} 

你接近:

boolean moveon; 
//... 
onCreate() { 
    moveon = false; 
//... 

// Still in UI thread here 
Handler myh = new Handler(); 
final Resources res = getResources(); // final so we can access it inside second thread 
new Thread(new Runnable() { 
    public void run() { 
     // In second thread 
     for(int i=0; i<3; i++){ 
      // Now we use the Handler to post back to the UI thread from the second thread 
      myh.post(new Runnable() { 
       public void run() { 
        // In UI thread, update here and then invalidate 
        id = res.getIdentifier("txt"+Integer.toString(winners[i]), "id", 
        getApplicationContext().getPackageName());  
        TextView temp = (TextView)findViewById(id); 
        temp.setBackgroundColor(Color.parseColor("#ffd700")); 
        temp.getBackground().setAlpha(127); 
        temp.postInvalidate(); 
       } 
      }); 

      Thread.sleep(delayMs); // Sleep second thread 
     } 
     myh.post(new Runnable() { 
       public void run() { 
        // In UI thread, reset the moveon to true on correct thread 
        moveon = true; 
       } 
      }); 
    } 
}).start(); 

那麼就不要使用你的while循環,因爲這仍然會阻止用戶界面,並給你同樣的問題。你想要做的是在允許用戶做其他事情之前檢查moveon == true;沒有必要的循環。

+0

對於你來說,這看起來不錯,對''for'循環中的'int i'需要全局化,本地'i'不能從內部'run()'函數進行訪問。除此之外,這對我有用。現在我需要通讀幾遍,以確保我明白***爲什麼會有效。 :) – Mike

+0

你讓我在那裏XD但很高興你明白了! – Guardanis

0

不知道如果它真的適合您的具體要求,但你可以通過設置延遲與ValueAnimator嘗試更新動畫顏色。

這是我用兩個textviews嘗試的示例代碼。

final TextView textView1 = (TextView) findViewById(R.id.textView1); 
    final TextView textView2 = (TextView) findViewById(R.id.textView2); 

    final ValueAnimator colorAnimation1 = ValueAnimator.ofObject(new ArgbEvaluator(), Color.YELLOW, Color.YELLOW); 
    final ValueAnimator colorAnimation2 = ValueAnimator.ofObject(new ArgbEvaluator(), Color.YELLOW, Color.YELLOW); 

    colorAnimation1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 

     @Override 
     public void onAnimationUpdate(ValueAnimator animator) { 
      textView1.setBackgroundColor((Integer) animator.getAnimatedValue()); 
      colorAnimation2.setStartDelay(500); 
      colorAnimation2.start(); 

     } 

    }); 
    colorAnimation1.setStartDelay(500); 
    colorAnimation1.start(); 

    colorAnimation2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 

     @Override 
     public void onAnimationUpdate(ValueAnimator animator) { 
      textView2.setBackgroundColor((Integer) animator.getAnimatedValue()); 
     } 
    }); 
+0

是的......那也可以,我也考慮過使用動畫,但它現在有同樣的問題。 ['startAnimation()'](http://developer.android.com/reference/android/view/View.html#startAnimation(android.view.animation.Animation)),據我所知,不無論如何,請繼續等待動畫完成後再繼續。作爲我的要求的一部分,我想在我的主線程運行之前等待所有三個背景完成變色。 – Mike

相關問題