2011-03-05 8 views
24

He estado jugando con la programación de Android de forma intermitente durante un par de semanas, y estoy tratando de hacer algo que parece simple, pero creo que me falta algo.En Android, ¿cómo puedo desvanecer suavemente el fondo de un color a otro? (Cómo usar los hilos)

Lo que intento hacer es fundir suavemente el fondo de, digamos, blanco a negro.

He intentado algunas cosas, ninguna de las cuales parece funcionar.

Lo primero que hice fue utilizar un bucle for y el método setBackgroundColor para LinearLayout, cambiando los valores R, G y B juntos de 0 a 255. No funciona.

Puedo hacer uno de los cambios de configuración, pero cuando hago el ciclo obtengo nada más que el último valor. Lo que creo que está sucediendo es que la IU se está bloqueando mientras el ciclo está en progreso y se está descongelando cuando termina el ciclo. Intenté poner retrasos en el ciclo (retrasos de bucle anidados feos y Thread.sleep), todo fue en vano.

¿Alguien me puede dar alguna indicación sobre cómo hacer que esto funcione? ¿Necesito un segundo hilo para hacer el cambio al color? Tengo una idea vaga de los hilos, aunque nunca los he usado.

Mi código de ejemplo que muestra más o menos lo que yo estoy tratando de hacer es la siguiente:

main.xml es:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:id="@+id/screen" 
    > 
<TextView 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello" 
    /> 
</LinearLayout> 

Y mi código de Java es (el 0,01 Inc es sólo para actuar como. un mecanismo de retardo feo para tratar de ver la visualización de los colores cambian lentamente):

package nz.co.et.bgfader; 

import android.app.Activity; 
import android.os.Bundle; 
import android.widget.LinearLayout; 

public class bgfader extends Activity { 

    LinearLayout screen; 

/** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     screen = (LinearLayout) findViewById(R.id.screen); 
     for (int i = 0; i < 65535; i+=0.01) { 
      screen.setBackgroundColor(0xff000000 + i); 
     } 
    } 
} 

Cualquier ayuda sería muy apreciada

Saludos

Steve

Respuesta

11

En su bucle, su ajuste en el fondo es tan rápido que la interfaz de usuario no es (no) capaz de programar la actualización de la pantalla. Sí, será mejor que use un segundo hilo para actualizar el fondo o de lo contrario se detendrá el hilo de la interfaz de usuario. Intente lo siguiente:

LinearLayout screen; 
Handler handler = new Handler(); 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    screen = (LinearLayout) findViewById(R.id.screen); 

    (new Thread(){ 
     @Override 
     public void run(){ 
      for(int i=0; i<255; i++){ 
       handler.post(new Runnable(){ 
        public void run(){ 
         screen.setBackgroundColor(Color.argb(255, i, i, i)); 
        } 
       }); 
       // next will pause the thread for some time 
       try{ sleep(10); } 
       catch{ break; } 
      } 
     } 
    }).start(); 
} 

Esta es una versión enhebrada de su código.

+5

¡Gracias! :) Eso lo hizo funcionar, con algunos cambios menores. Tuve que hacer que fuera global, ya que no se podía acceder dentro del método de ejecución de lo contrario (o podría haberlo pasado, supongo). También tuve que ajustar el try/catch ya que no compilaría para mí tal como estaba. Muchas gracias, eso me ha estado volviendo loco durante un par de días. Voy a jugar con los hilos y ver si puedo hacer algo interesante con este código ahora está funcionando. – Steve

+3

Esta no es una buena práctica. No está permitido actualizar la interfaz de usuario de un hilo BG. La sugerencia de @ Amy es la correcta. Está el proyecto http://nineoldandroids.com/ que implementa el ObjectAnimator para Android anterior a 3.0 – tofi9

+0

¿Qué sucede si quiero desvanecer un color a otro usando un valor 'seekbar' en' TextView'? – Si8

85

he encontrado otra manera de cambiar el color de fondo si usted está interesado - Creo que el uso de la animación será más fácil que lo que actualmente tiene :)

Si está utilizando la API de nivel 11 o superior, que pueda utilice ObjectAnimator en el color de fondo de su LinearLayout.

ObjectAnimator colorFade = ObjectAnimator.ofObject(screen, "backgroundColor", new ArgbEvaluator(), Color.argb(255,255,255,255), 0xff000000); 
    colorFade.setDuration(7000); 
    colorFade.start(); 

Además, solo una nota rápida, se deben usar los códigos de color int de 32 bits. Consulte http://developer.android.com/reference/android/graphics/Color.html para obtener más detalles, pero puede usar Color.argb, Color.rgb, el hexágono como utilicé anteriormente, o ver las constantes de color int.

Espero que esto ayude!

+0

Gracias por eso, estaba usando 2.2, por lo que esta solución no hubiera funcionado ... y dado que era para una aplicación de luz de noche para mi hija, y su tableta estaba basada en 2.2, habría necesitado seguir con la original opción roscada ... pero me gusta de esta manera por su simplicidad, así que podría tener un truco con ella. Cheers – Steve

+0

Realmente es bueno saberlo. Es una pena solo para 3.0+. buscando una solución similar para 2.2/2.3 + – speedynomads

+0

Great api finding. –

3

Si alguien está buscando una solución pre 3.0, Nine Old Androids le permitirá usar la API de animación en los dispositivos de nuevo a Android 1.0.http://nineoldandroids.com/

1

un par de soluciones para dispositivos antiguos:

TIMER

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    final Timer myTimer = new Timer(); 
    final View myview = getWindow().getDecorView().findViewById(
      android.R.id.content); 

    myTimer.schedule(new TimerTask() { 
     int color = 0; 
     @Override 
     public void run() { 
      // If you want to modify a view in your Activity 
      runOnUiThread(new Runnable() { 
       public void run() { 
        color++; 
        myview.setBackgroundColor(Color.argb(255, color, color, 
          color)); 
        if (color == 255) 
         myTimer.cancel(); 
       } 
      }); 
     } 
    }, 1000, 20); // initial delay 1 second, interval 1 second 

} 

HILO

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    new Thread() { 
     int color = 0; 
     View myview = getWindow().getDecorView().findViewById(
       android.R.id.content); 
     @Override 
     public void run() { 
      for (color = 0; color < 255; color++) { 
       try { 
        sleep(20); 
        runOnUiThread(new Runnable() { 
         @Override 
         public void run() { 
          myview.setBackgroundColor(Color.argb(255, 
            color, color, color)); 
         } 
        }); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    }.start(); 
} 
4

mejor respuesta a esta pregunta sería utilizar ObjectAnimator

ObjectAnimator colorFade = ObjectAnimator.ofObject(view, "backgroundColor" /*view attribute name*/, new ArgbEvaluator(), mContext.getResources().getColor(R.color.colorMenuOverlay) /*from color*/, Color.WHITE /*to color*/); 
       colorFade.setDuration(3500); 
       colorFade.setStartDelay(200); 
       colorFade.start(); 
Cuestiones relacionadas