Comment forcer l'actualisation d'une vue de mise en page entière?

173

Je veux forcer la vue principale des ressources de mise en page à redessiner / actualiser, par exemple la méthode Activity.onResume (). Comment puis-je faire ceci ?

Par vue de mise en page principale, j'entends celle ('R.layout.mainscreen' ci-dessous) qui est appelée dans mon Activity.onCreate (), comme ceci: -

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mainscreen);
}
MickeyR
la source
Avez-vous essayé de nommer votre Linear / Relative / WhateverLayout englobant, d'appeler findViewById dessus, puis d'appeler invalidate () sur cela? (Je mettrais cela comme une réponse, mais je ne sais pas si invalider les parents invalide également les enfants et je ne suis pas quelque part où je puisse le tester.)
Ben Williams
Merci aussi ! J'ai encore du mal avec ça. Pouvez-vous jeter un œil à ce que j'ai publié ci-dessous. J'ai besoin de ce code (ou autre?) Pour que mon thème soit actualisé ...
MickeyR

Réponses:

149

Pour répondre strictement à la question: utilisez invalidate ():

public void invalidate () Depuis: API niveau 1

Invalidez la vue entière. Si la vue est visible, onDraw (Canvas) sera appelé à un moment donné dans le futur. Cela doit être appelé à partir d'un thread d'interface utilisateur. Pour appeler à partir d'un thread non-UI, appelez postInvalidate ().

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

Désormais, lorsque l'activité reprend, chaque vue se dessine d'elle-même. Aucun appel à invalidate () ne devrait être nécessaire. Pour appliquer le thème, assurez-vous de le faire avant toute vue, c'est-à-dire avantsetContentView(R.layout.mainscreen);

public void setTheme (int resid) Depuis: API Niveau 1

Définissez le thème de base pour ce contexte. Notez que cela doit être appelé avant que les vues ne soient instanciées dans le contexte (par exemple avant d'appeler setContentView (View) ou inflate (int, ViewGroup)).

La référence de la documentation de l'API est ici: http://developer.android.com/reference/android/view/ContextThemeWrapper.html#setTheme%28int%29

Puisque la méthode onDraw () fonctionne sur des vues déjà instanciées, setTheme ne fonctionnera pas. Je n'ai moi-même aucune expérience des thèmes, mais je peux penser que deux options alternatives sont:

  1. appelez setTheme dans onCreate () à la place, ou
  2. refaire setContentView (R.layout.mainscreen); pour forcer à rétablir toute la mise en page.
Aleadam
la source
Merci ! Cela fonctionne bien, mais je ne vois pas ce à quoi je m'attendais. Juste avant d'exécuter votre code, j'exécute Activity.setTheme (newtheme) mais cet appel invalidate () ne fait pas changer le thème (par exemple de Dark à Light). Invalider () devrait-il être capable de le faire?
MickeyR
@MickeyR non, ça ne devrait pas. Vérifiez ma réponse mise à jour. Si ces deux options ne fonctionnent pas, vous devrez redémarrer votre activité.
Aleadam
L'option (1) fonctionne. Mon application démarrera avec le bon thème, mais si je le change en cours d'exécution, je dois redémarrer mon application pour que onCreate () soit à nouveau appelé.
MickeyR
L'option (2) est l'itinéraire que je voulais emprunter. Donc, lorsque le thème est changé pendant l'exécution, je voulais que onRestart () fasse ceci: - setTheme (getPreferenceTheme ()); et setContentView (R.layout.main); Mais cela ne change pas mon thème. Je ne peux pas faire fonctionner cette deuxième option ...?!
MickeyR
J'ai compris que pour que l'option (2) fonctionne, je devais «regonfler la hiérarchie des vues». J'ai essayé différentes choses pour y parvenir, mais je ne sais pas vraiment ce que cela signifie ni comment le faire.
MickeyR
41

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

claviériste
la source
3
Merci ! Même réponse que j'ai postée ci-dessus sur Aleadam. Cette invalidation () ne provoque pas l'actualisation du thème d'activité, ce dont j'ai besoin.
MickeyR
36

Si recreate()vous essayez , cette activité sera recréée.

Mohanad ALKHOULI
la source
4
J'ai essayé toutes les options de ce fil, et c'est la seule qui a fonctionné avec les effets secondaires les moins indésirables.
swooby
1
Que faire si j'ai besoin de cela dans la onResumeméthode. Cela me donne une boucle infinie: /
Kamil Witkowski
Eh bien, je ne recommande pas de l'utiliser avant d'en avoir vraiment besoin. Vous pouvez enregistrer un indicateur dans les préférences partagées pour éviter la boucle infinie.
Mohanad ALKHOULI
cela fonctionne mais je ne recommanderais pas de l'utiliser dans une application en mode production réelle. Je n'en avais besoin que pour le mode débogage, donc l'effet secondaire de l'actualisation de toute l'interface utilisateur n'est pas critique.
drorsun
31

Solution:

Les gars, j'ai essayé toutes vos solutions mais elles n'ont pas fonctionné pour moi, je dois définir setVisibility of EditText sur VISIBLE et cet EditText devrait être visible alors dans ScrollView , mais je n'ai pas pu actualiser la vue racine pour prendre effet. J'ai résolu mon problème, lorsque j'ai besoin d'actualiser la vue, j'ai donc changé la visibilité de ScrollView sur GONE, puis à nouveau la définir sur VISIBLE pour prendre effet et cela a fonctionné pour moi. Ce n'est pas la solution exacte mais cela a seulement fonctionné.

 private void refreshView(){
    mScrollView.setVisibility(View.GONE);
    mScrollView.setVisibility(View.VISIBLE);
}
Naveed Ahmad
la source
2
@MickeyR Veuillez accepter une réponse, afin que les gens puissent trouver la solution facilement
Naveed Ahmad
wow .. J'ai aussi essayé toutes les sollutions proposées mais cela semble être le seul qui fonctionne, mais c'est assez horrible ...
Rik van Velzen
Je ne sais pas pourquoi @MickeyR n'accepte pas cette réponse
Naveed Ahmad
1
@NaveedAhmad Merci! Après 4 heures à faire tout ce que je pouvais, c'était la seule solution qui fonctionnait.
Codelicious
10

L'appel invalidate()ou postInvalidate()sur la mise en page racine ne garantit apparemment PAS que les vues enfants seront redessinées. Dans mon cas spécifique, ma disposition racine était un TableLayout et avait plusieurs enfants de classe TableRow et TextView. L'appel postInvalidate(), ou requestLayout()même forceLayout()sur l'objet racine TableLayout, n'a provoqué le redessinage d'aucun TextViews dans la mise en page.

Donc, ce que j'ai fini par faire était d'analyser récursivement la mise en page à la recherche de ces TextViews, puis d'appeler postInvalidate()chacun de ces objets TextView.

Le code peut être trouvé sur GitHub: https://github.com/jkincali/Android-LinearLayout-Parser

jkincali
la source
9

Sinon, vous pouvez essayer ceci aussi-

ViewGroup vg = (ViewGroup) findViewById (R.id.videoTitleTxtView);
 vg.removeAllViews();
 vg.refreshDrawableState();
Datta Kunde
la source
4
Merci pour cela ! Mais, cela a supprimé toutes les vues que j'avais (TextView, boutons, etc.) mais ne les a pas redessinées - mon écran est resté vide ...
MickeyR
vous devez actualiser votre vue à droite, puis appeler à nouveau la fonction de dessin. après avoir nettoyé la vue précédente.
Datta Kunde
4

Définissez simplement votre vue de contenu dans onresume

setContentView (R.layout.yourview) dans onResume ..

Exemple:

@Override
public void onResume(){
super.onResume();
setContentView(R.layout.activity_main); 
postIncomeTotals();
}
Farhan
la source
Salut, j'ai essayé ceci et les mêmes données dans la liste sont tirées deux fois, donc si j'avais 4 lignes et que le rafraîchissement était censé ajouter une cinquième ligne, je me retrouve à la place avec 10, puis 15, ... que faire?
iOSAndroidWindowsMobileAppsDev
4

Essayez cette solution de contournement pour le problème de thème:

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

Cela vous permet de recharger avec les changements de thème et masque les animations.

Code inversé
la source
3

J'avais également ce problème, mais en suivant l'exemple de Farhan, setContentView()je l'ai fait. l’utilisation setContentView()en elle-même n’était cependant pas suffisante. J'ai constaté que je devais repeupler toutes mes opinions avec des informations. Pour résoudre ce problème, je viens de tirer tout ce code vers une autre méthode (je l'ai appelée build) et dans ma onCreateméthode, j'appelle simplement cette build. Désormais, chaque fois que mon événement se produit et que je veux que mon activité se «rafraîchisse», j'appelle simplement build, je lui donne les nouvelles informations (que je transmets en tant que paramètres à construire) et j'ai une activité actualisée.

user3612162
la source
2

Cela semble être un bogue connu .

Ben Williams
la source
setTheme fonctionne lorsque je redémarre mon activité (appelez finish () puis startActivity ()). Je n'arrive tout simplement pas à actualiser le thème sans redémarrer mon activité ...
MickeyR
0

Je ne sais pas si c'est sûr ou non, mais cela a fonctionné pour moi. J'ai en quelque sorte rencontré ce problème moi-même et j'ai essayé invalidate(), requestLayout()mais en vain. Alors je viens de m'appeler onCreate(null)à nouveau et ça a marché. Si cela n'est pas sûr, veuillez me le faire savoir. J'espère que cela aide quelqu'un là-bas.

Cai
la source
Vous définissez le savedInstanceState sur null, ce qui pourrait provoquer un comportement inattendu. Pour plus d'informations: stackoverflow.com/questions/15115975/…
PhilipB
0

Voici comment j'actualisais ma mise en page

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

Pour effacer une vue étendant ViewGroup, il vous suffit d'utiliser la méthode removeAllViews()

Juste comme ça (si vous avez un ViewGroup appelé myElement):

myElement.removeAllViews()
Jack'
la source
0

Essaye ça

view.requestLayout();
Milind Chaudhary
la source
-1

Je ne sais pas si c'est une bonne approche, mais j'appelle simplement ceci à chaque fois:

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

Rappelez simplement l'activité elle-même en utilisant l'intention. Par exemple, pour actualiser la disposition de MainActivity, procédez comme suit:

startActivity(new Intent(MainActivity.this, MainActivity.class));
Anshul Aggarwal
la source
2
C'est moche! Lorsque vous faites cela, vous ajoutez simplement une nouvelle activité sur la pile, donc, lorsque vous appuyez sur le bouton Retour, vous revenez à la même activité.
Daniel Beltrami