2014-03-31 12 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

相关问题