¿Cómo forzar una actualización completa de Vista de diseño?

173

Quiero forzar la vista de recursos de diseño principal para volver a dibujar / actualizar, por ejemplo, en el método Activity.onResume (). Cómo puedo hacer esto ?

Por vista de diseño principal, me refiero a la ('R.layout.mainscreen' a continuación) que se llama en mi Activity.onCreate (), así:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mainscreen);
}
MickeyR
fuente
¿Has intentado nombrar tu Linear / Relative / WhateverLayout adjunto, llamando a findViewById en él y luego llamando invalidate () en eso? (Yo pondría esto como respuesta, pero no sé si invalidar a los padres también invalida a los niños y no estoy en algún lugar donde pueda probarlo)
Ben Williams
Gracias tambien ! Aunque todavía estoy luchando con esto. ¿Puedes echar un vistazo a lo que he publicado a continuación? Necesito el código para hacer que mi tema para actualizar ... (o de otro tipo?)
MickeyR

Respuestas:

149

Para responder estrictamente la pregunta: Use invalidate ():

public void invalidate () Desde: API Nivel 1

Invalidar toda la vista. Si la vista es visible, se llamará a onDraw (Canvas) en algún momento en el futuro. Esto debe llamarse desde un hilo de la interfaz de usuario. Para llamar desde un subproceso que no sea UI, llame a postInvalidate ().

ViewGroup vg = findViewById (R.id.mainLayout);
vg.invalidate();

Ahora, cuando se reanuda la Actividad, hace que cada Vista se dibuje sola. No se necesita una llamada para invalidar (). Para aplicar el tema, asegúrese de hacerlo antes de dibujar cualquier Vista, es decir, antessetContentView(R.layout.mainscreen);

public void setTheme (int resid) Desde: API Nivel 1

Establezca el tema base para este contexto. Tenga en cuenta que esto debería llamarse antes de que cualquier vista sea instanciada en el Contexto (por ejemplo, antes de llamar a setContentView (View) o inflate (int, ViewGroup)).

La referencia de documentación API está aquí: http://developer.android.com/reference/android/view/ContextThemeWrapper.html#setTheme%28int%29

Dado que el método onDraw () funciona en vistas ya instanciadas, setTheme no funcionará. No tengo experiencia con temas, pero dos opciones alternativas que puedo pensar son:

  1. llame a setTheme en onCreate () en su lugar, o
  2. rehacer setContentView (R.layout.mainscreen); para forzar la reinstalación de todo el diseño.
Aleadam
fuente
Gracias ! Esto funciona bien, pero no veo lo que esperaba. Justo antes de ejecutar su código, ejecuto Activity.setTheme (newtheme) pero esta llamada invalidate () no hace que el tema cambie (por ejemplo, de oscuro a claro). ¿Debería invalidar () poder hacer eso?
MickeyR
@MickeyR no, no debería. Verifica mi respuesta actualizada. Si esas dos opciones no funcionan, deberá reiniciar su Actividad.
Aleadam
La opción (1) funciona. Mi aplicación comenzará con el tema correcto, pero si lo cambio mientras se ejecuta, tengo que reiniciar mi aplicación para que se vuelva a llamar a onCreate ().
MickeyR
La opción (2) es la ruta que quería tomar. Entonces, cuando se cambia el tema mientras se ejecuta, quería que onRestart () hiciera esto: - setTheme (getPreferenceTheme ()); y setContentView (R.layout.main); Pero esto no cambia mi tema. No puedo hacer que esta segunda opción funcione ...?!
MickeyR
Comprendí que para que funcione la opción (2) necesito 'volver a inflar la jerarquía de vistas'. He intentado diferentes cosas para lograr esto, pero no estoy realmente seguro de lo que esto significa ni cómo hacerlo.
MickeyR
41

Tratar getWindow().getDecorView().findViewById(android.R.id.content).invalidate();

teclados
fuente
3
Gracias ! La misma respuesta que publiqué arriba para Aleadam. Esto invalidate () no hace que el tema de la actividad se actualice, que es lo que necesito.
MickeyR
36

Pruébelo recreate()hará que esta actividad se vuelva a crear.

Mohanad ALKHOULI
fuente
44
Probé todas las opciones en este hilo, y esta es la única que funcionó con los efectos secundarios menos indeseables.
swooby
1
¿Qué pasa si necesito hacer esto en el onResumemétodo? Esto me da un bucle infinito: /
Kamil Witkowski
Bueno, no recomiendo usarlo hasta que realmente lo necesites. Puede guardar alguna bandera en las preferencias compartidas para evitar el bucle infinito.
Mohanad ALKHOULI
esto funciona pero no recomendaría usarlo en la aplicación de modo de producción real. Solo lo necesitaba para el modo de depuración, por lo que el efecto secundario de toda la actualización de la interfaz de usuario no es crítico.
drorsun
31

Solución:

Chicos, probé todas sus soluciones, pero no funcionaron para mí, tengo que establecer setVisibility of EditText en VISIBLE y este EditText debería estar visible en ScrollView , pero no pude actualizar la vista raíz para que surta efecto. Resolví mi problema, cuando necesito actualizar la vista, así que cambié la visibilidad de ScrollView a GONE y luego la configuré de nuevo en VISIBLE para que surta efecto y funcionó para mí. Esta no es la solución exacta, pero solo funcionó.

 private void refreshView(){
    mScrollView.setVisibility(View.GONE);
    mScrollView.setVisibility(View.VISIBLE);
}
Naveed Ahmad
fuente
2
@MickeyR Por favor acepte una respuesta, para que las personas puedan encontrar la solución fácilmente
Naveed Ahmad
wow ... También probé todas las soluciones propuestas, pero esta parece ser la única que funciona, pero es horrible ...
Rik van Velzen
No sé por qué @MickeyR no acepta esta respuesta
Naveed Ahmad
1
@NaveedAhmad ¡Gracias! Después de 4 horas de hacer todo lo que pude, esta fue la única solución que funcionó.
Codelicious
10

Llamar invalidate()o postInvalidate()en el diseño raíz aparentemente NO garantiza que las vistas de los niños se redibujarán. En mi caso específico, mi diseño raíz era un TableLayout y tenía varios hijos de la clase TableRow y TextView. Las llamadas postInvalidate(), o requestLayout()incluso forceLayout()en el objeto TableLayout raíz no causaron que se volvieran a dibujar las TextViews en el diseño.

Entonces, lo que terminé haciendo fue analizar recursivamente el diseño buscando esas TextViews y luego invocar postInvalidate()cada uno de esos objetos TextView.

El código se puede encontrar en GitHub: https://github.com/jkincali/Android-LinearLayout-Parser

jkincali
fuente
9

De lo contrario, puedes probar esto también:

ViewGroup vg = (ViewGroup) findViewById (R.id.videoTitleTxtView);
 vg.removeAllViews();
 vg.refreshDrawableState();
Datta Kunde
fuente
44
Gracias por esto ! Sin embargo, esta eliminadas todas las vistas que tenía (Vista de Texto, botones, etc) pero no re-dibujarlos - mi pantalla permaneció en blanco ...
MickeyR
debe actualizar su vista correctamente, luego debe llamar a la función de dibujo nuevamente. después de limpiar la vista anterior.
Datta Kunde
4

Simplemente configure su vista de contenido en un resumen

setContentView (R.layout.yourview) dentro de onResume ..

Ejemplo:

@Override
public void onResume(){
super.onResume();
setContentView(R.layout.activity_main); 
postIncomeTotals();
}
Farhan
fuente
Hola, probé esto y los mismos datos en la vista de lista se extraen dos veces, por lo tanto, si tenía 4 filas y se suponía que la actualización agregaba una quinta fila, en su lugar termino con 10, luego 15, ... ¿qué debo hacer?
iOSAndroidWindowsMobileAppsDev
4

Pruebe esta solución alternativa para el problema de tema:

@Override
public void onBackPressed() {
    NavUtils.navigateUpTo(this, new Intent(this,
            MyNeedToBeRefreshed.class));
}
Krilivye
fuente
3
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);

Esto le permite recargar con cambios de tema y oculta las animaciones.

Codeversed
fuente
3

También tenía este problema, pero siguiendo el ejemplo de Farhan de usar setContentView(), hice exactamente eso. setContentView()Sin embargo, el uso por sí solo no era suficiente. Descubrí que tenía que repoblar todas mis opiniones con información. Para solucionar esto, simplemente extraje todo ese código a otro método (lo llamé compilación) y en mi onCreatemétodo simplemente llamo a esa compilación. Ahora, cada vez que ocurre mi evento que quiero que mi actividad se "actualice", simplemente llamo a build, le doy la nueva información (que paso como parámetros para compilar) y tengo una actividad actualizada.

usuario3612162
fuente
2

Esto parece ser un error conocido .

Ben Williams
fuente
setTheme funciona find cuando reinicio mi actividad (call finish () y luego startActivity ()). Simplemente no puedo hacer que actualice el tema sin reiniciar mi actividad ...
MickeyR
0

No sé si esto es seguro o no, pero funcionó para mí. Yo un poco encontré con este problema y traté invalidate()y requestLayout()pero fue en vano. Así que llamé a mi onCreate(null)nuevo y funcionó. Si esto no es seguro, hágamelo saber. Espero que esto ayude a alguien por ahí.

Cai
fuente
Está configurando saveInstanceState en nulo, lo que podría causar un comportamiento inesperado. Para más información: stackoverflow.com/questions/15115975/…
PhilipB
0

Así es como solía actualizar mi diseño

Intent intent = getIntent();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);
sivaBE35
fuente
0

Para borrar una vista que extiende ViewGroup, solo necesita usar el método removeAllViews()

Así (si tiene un ViewGroup llamado myElement):

myElement.removeAllViews()
Jack'
fuente
0

Prueba esto

view.requestLayout();
Milind Chaudhary
fuente
-1

No estoy seguro de si es un buen enfoque, pero solo lo llamo cada vez:

setContentView(R.layout.mainscreen);
Krzysztof Tkacz
fuente
-8

Simplemente llame a la actividad nuevamente utilizando la intención. Por ejemplo, para actualizar el diseño de MainActivity, haga lo siguiente:

startActivity(new Intent(MainActivity.this, MainActivity.class));
Anshul Aggarwal
fuente
2
¡Eso es feo! Cuando hace esto, simplemente agrega una nueva actividad en la pila, por lo que, cuando presiona el botón Atrás, volverá a la misma actividad.
Daniel Beltrami