2012-01-06 10 views
19

Tengo un LinearLayout que me gustaría cambiar el color de fondo cuando se hace clic en una de sus vistas secundarias (un ImageButton). Puedo hacer esto, pero no de inmediato: el cambio no ocurre en la pantalla hasta más tarde (creo que durante una llamada a respuesta). Me gustaría descubrir cómo forzar el diseño para volver a dibujar después de que se establece el fondo, antes de que se ejecute la siguiente línea de código. Aquí está el método onClick de mi OnClickListener para el botón:Cómo forzar una vista para volver a dibujar inmediatamente antes de ejecutar la siguiente línea de código

comando
public void onClick(View v) { 

    LinearLayout parentLayout = (LinearLayout) v.getParent(); 
    parentLayout.setBackgroundResource(R.color.my_color); 
    SystemClock.sleep(1000); //ms 

} 

El sueño está ahí para probar si el redibujado ocurre antes o después de ella. El resultado: después. La mayoría de las preguntas sobre este tema (como here y here) dicen usar invalidate() en la vista. He utilizado los comandos parentLayout.invalidate();, parentLayout.postInvalidate(); y parentLayout.refreshDrawableState(); entre las líneas de fondo y de suspensión, todo en vano. El redraw aún ocurre después del comando de suspensión. ¿Alguien puede decirme cómo hacer que suceda de inmediato?

Otra información posiblemente útil: LinearLayout está vinculado a las filas de un ListView, y el OnClickListener anterior está en una clase personalizada que extiende SimpleCursorAdapter, no en la actividad misma. (De esta forma puedo configurar un oyente para cada una de las filas en el ListView.)

+0

Parece que no obtendrá la respuesta exacta para esto, al menos no pude encontrar uno. ¿Puede decirnos por qué necesita que la vista se vuelva a dibujar de inmediato? Puede haber otras soluciones para resolver el problema. – manjusg

+0

@manjusg Lo que intento hacer es lo que normalmente se hace con el selector de fondo de una vista en xml (el fondo cambia brevemente de color cuando se presiona justo antes de ejecutar su devolución de llamada), excepto que quiero cambiar el fondo de una vista diferente el botón que se presiona, es decir, el diseño que contiene el botón y también una vista de texto. – pvans

+0

@manjusg Las filas de mi vista de lista tienen texto y un botón para eliminar, y me gustaría que la fila completa, incluida la vista de texto, se resalte brevemente antes de eliminarla y eliminarla, para que el usuario tenga algún comentario de que ha presionado el botón fila que quiso. Tal vez hay alguna forma de cruzar vistas de enlace con un selector en xml? – pvans

Respuesta

2

Bien, finalmente encontré una solución a este problema, y ​​es simple. Parece que el problema fue que estaba ejecutando los cambios dibujables en un OnClickLIstener, cuando debería haberlo hecho en un OnTouchListener. Si configuro OnTouchListener para mi botón que busca ACTION_DOWN y luego ejecuta setBackgroundColor en su diseño principal, el cambio se produce de inmediato.

Una solución alternativa menos robusta viene de this post. Puede asignar un selector para el fondo de diseño principal en xml, luego, en el OnTouchListener mencionado anteriormente, ejecute setPressed (true) en ese diseño. No es una gran solución porque el selector te ofrece mucha menos libertad que cambiar directamente las propiedades de la vista en el código. No puede establecer el fondo del diseño en un color diferente presionando un botón diferente, por ejemplo.

Gracias a los que ayudaron con sugerencias sobre esto!

1

realice los cambios y llame a listview.invalidate(); para reflejar esos cambios en la interfaz de usuario

+0

No tengo acceso directo a ListView en este código, ya que está en la clase de adaptador, no en la actividad. Puedo hacer referencia alListView usando esta línea: 'mActivity.mListView.invalidate();' (mActivity es la actividad de llamada extraída del Contexto, mListView es un campo público de la actividad que hace referencia al ListView), pero insertando esta línea antes del dormir aún no soluciona el problema. – pvans

3

Puede intentar forceLayout() con una llamada a draw(canvas) inmediatamente después. Si no anuló onLayout(), onMeasure, draw() o onDraw(), se ejecutará la implementación predeterminada. El único problema con esto es que debes obtener el lienzo o crear uno manualmente.

Se desaconseja encarecidamente seguir este enfoque, ya que Android está específicamente diseñado para evitar el dibujo fuera de las actualizaciones normales. Si bien tienes razón de decir que invalidate() no ocurre de inmediato, es la forma más segura y la mejor manera de alentar un redibujado. Si desea controlar el dibujo fuera de las actualizaciones, Android proporciona una forma de hacerlo con la clase SurfaceHolder.

+0

Hmm. Creo que preferiría evitar las prácticas desalentadas. Estoy agregando más información acerca de lo que intento lograr como comentario en la pregunta. – pvans

+0

Dicho esto, algo a tener en cuenta: las directrices de Android recomiendan encarecidamente no bloquear nunca el hilo de la interfaz de usuario por algún motivo. Al colocar el comando 'SystemClock.sleep()', está bloqueando el subproceso de la interfaz de usuario. Si esto es para pruebas teóricas, ¡increíble! Por favor, háganos saber sus hallazgos. Si esto es para una aplicación en el mundo real, consideraría fuertemente que reanalizas tu programa. –

+0

El sueño es solo para probar. Por curiosidad, ¿cómo recomendarías implementar una pausa, por ejemplo, entre un clic y la acción de devolución de llamada asociada? – pvans

Cuestiones relacionadas