Jak wymusić odświeżenie całego widoku układu?


173

Chcę wymusić ponowne rysowanie / odświeżanie głównego widoku zasobów układu, na przykład metody Activity.onResume (). W jaki sposób mogę to zrobić ?

Przez główny widok układu mam na myśli ten („R.layout.mainscreen” poniżej), który jest wywoływany w moim Activity.onCreate (), na przykład: -

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mainscreen);
}

Czy próbowałeś nazwać otaczający ją Linear / Relative / WhatersLayout, wywołać na nim findViewById, a następnie wywołać na nim invalidate ()? (Powiedziałbym to jako odpowiedź, ale nie wiem, czy unieważnienie rodziców również unieważnia dzieci i nie jestem gdzieś, w którym mógłbym to sprawdzić.)
Ben Williams

Dziękuję również ! Nadal jednak z tym walczę. Czy możesz spojrzeć na to, co zamieściłem poniżej. Potrzebuję tego kodu (lub innego?), Aby spowodować odświeżenie mojego motywu ...
MickeyR

Odpowiedzi:


149

Aby ściśle odpowiedzieć na pytanie: Użyj unieważnienia ():

public void invalidate () Od: API poziom 1

Unieważnij cały widok. Jeśli widok jest widoczny, w przyszłości zostanie wywołane onDraw (Canvas). To musi być wywołane z wątku interfejsu użytkownika. Aby wywołać z wątku spoza interfejsu użytkownika, wywołaj postInvalidate ().

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

Teraz, gdy działanie zostanie wznowione, każdy widok sam się narysuje. Nie powinno być potrzebne wywołanie unieważnienia (). Aby zastosować motyw, upewnij się, że robisz to przed narysowaniem jakiegokolwiek widoku, tj. PrzedsetContentView(R.layout.mainscreen);

public void setTheme (int Resid) Od: API Poziom 1

Ustaw motyw podstawowy dla tego kontekstu. Należy zauważyć, że należy to wywołać przed utworzeniem wystąpienia jakichkolwiek widoków w Context (na przykład przed wywołaniem setContentView (View) lub inflate (int, ViewGroup)).

Dokumentacja dotycząca interfejsu API znajduje się tutaj: http://developer.android.com/reference/android/view/ContextThemeWrapper.html#setTheme%28int%29

Ponieważ metoda onDraw () działa na już utworzonych widokach, setTheme nie będzie działać. Sam nie mam doświadczenia z motywami, ale myślę, że dwie alternatywne opcje to:

  1. zamiast tego wywołaj setTheme w onCreate () lub
  2. ponów setContentView (R.layout.mainscreen); wymusić przywrócenie całego układu.

Dzięki ! Działa dobrze, ale nie widzę, czego się spodziewałem. Tuż przed uruchomieniem twojego kodu uruchamiam Activity.setTheme (newtheme), ale to wywołanie invalidate () nie powoduje zmiany motywu (np. Z Dark na Light). Czy invalidate () powinno móc to zrobić?
MickeyR

@MickeyR nie, nie powinno. Sprawdź moją zaktualizowaną odpowiedź. Jeśli te dwie opcje nie zadziałają, konieczne będzie ponowne uruchomienie działania.
Aleadam

Opcja (1) działa. Moja aplikacja uruchomi się z poprawnym motywem, ale jeśli zmienię go podczas działania, muszę ponownie uruchomić aplikację, aby ponownie wywołać onCreate ().
MickeyR

Opcja (2) to trasa, którą chciałem wybrać. Tak więc, gdy motyw zostanie zmieniony podczas działania, chciałem, aby onRestart () zrobił to: - setTheme (getPreferenceTheme ()); i setContentView (R.layout.main); Ale to nie zmienia mojego motywu. Nie mogę uruchomić tej drugiej opcji ...?!
MickeyR

Zrozumiałem, że aby opcja (2) działała, muszę „ponownie wypełnić hierarchię widoków”. Próbowałem różnych rzeczy, aby to osiągnąć, ale nie jestem pewien, co to oznacza ani jak to zrobić.
MickeyR

41

Próbować getWindow().getDecorView().findViewById(android.R.id.content).invalidate();


3
Dzięki ! Ta sama odpowiedź, którą zamieściłem powyżej dla Aleadam. To unieważnienie () nie powoduje odświeżenia motywu działania, czego potrzebuję.
MickeyR

36

Wypróbuj recreate()to spowoduje odtworzenie tego działania.


4
Wypróbowałem wszystkie opcje w tym wątku i jest to jedyna, która działała z najmniej niepożądanymi efektami ubocznymi.
swooby

1
Co jeśli potrzebuję tego w onResumemetodzie. To daje mi nieskończoną pętlę: /
Kamil Witkowski

Cóż, nie polecam go używać, dopóki naprawdę nie potrzebujesz. Możesz zapisać niektóre flagi we wspólnych preferencjach, aby uniknąć nieskończonej pętli.
Mohanad ALKHOULI

to działa, ale nie polecam używania go w aplikacji w trybie produkcyjnym. Potrzebowałem go tylko do trybu debugowania, więc efekt uboczny odświeżania całego interfejsu użytkownika nie jest krytyczny.
drorsun

31

Rozwiązanie:

Chłopaki, wypróbowałem wszystkie Twoje rozwiązania, ale nie zadziałały, muszę ustawić setVisibility of EditText na VISIBLE i ten EditText powinien być wtedy widoczny w ScrollView , ale nie mogłem odświeżyć widoku głównego, aby odniosło skutek. Rozwiązałem problem, kiedy muszę odświeżyć widok, więc zmieniłem widoczność ScrollView na GONE, a następnie ponownie ustawiłem ją na VISIBLE, aby odniosła skutek i zadziałało. To nie jest dokładne rozwiązanie, ale tylko działało.

 private void refreshView(){
    mScrollView.setVisibility(View.GONE);
    mScrollView.setVisibility(View.VISIBLE);
}

2
@MickeyR Proszę, zaakceptuj odpowiedź, aby ludzie mogli łatwo znaleźć rozwiązanie
Naveed Ahmad

wow .. Wypróbowałem też wszystkie proponowane rozwiązania, ale wydaje się, że jedyne działające, ale to trochę okropne ...
Rik van Velzen

Nie wiem, dlaczego @MickeyR nie akceptuje tej odpowiedzi
Naveed Ahmad

1
@NaveedAhmad Dziękuję! Po 4 godzinach robienia wszystkiego, co mogłem, było to jedyne rozwiązanie, które zadziałało.
Codelicious

10

Wywołanie invalidate()lub postInvalidate()w układzie głównym najwyraźniej NIE gwarantuje, że widoki potomne zostaną przerysowane. W moim konkretnym przypadku moim układem głównym był TableLayout i miał kilka elementów podrzędnych klasy TableRow i TextView. Wywołanie postInvalidate(), a requestLayout()nawet forceLayout()w głównym obiekcie TableLayout, nie spowodowało ponownego narysowania żadnych TextViews w układzie.

W końcu to, co zrobiłem, to rekurencyjne analizowanie układu w poszukiwaniu tych TextViews, a następnie wywoływanie postInvalidate()każdego z tych obiektów TextView.

Kod można znaleźć na GitHub: https://github.com/jkincali/Android-LinearLayout-Parser


9

W przeciwnym razie możesz spróbować również tego -

ViewGroup vg = (ViewGroup) findViewById (R.id.videoTitleTxtView);
 vg.removeAllViews();
 vg.refreshDrawableState();

4
Dzięki za to ! Ale to usunęło wszystkie widoki, które miałem (TextView, przyciski itp.), Ale nie narysowałem ich ponownie - mój ekran pozostał pusty ...
MickeyR

musisz odpowiednio odświeżyć widok, a następnie ponownie wywołać funkcję rysowania. po wyczyszczeniu poprzedniego widoku.
Datta Kunde

4

Po prostu ustaw widok treści w trybie onresume

setContentView (R.layout.yourview) wewnątrz onResume ..

Przykład:

@Override
public void onResume(){
super.onResume();
setContentView(R.layout.activity_main); 
postIncomeTotals();
}

Cześć, próbowałem tego i te same dane w widoku listy są pobierane dwukrotnie, stąd gdybym miał 4 wiersze i odświeżanie miało dodać piąty wiersz, zamiast tego skończyło się na 10, potem 15, ... co t zrobić?
iOSAndroidWindowsMobileAppsDev

4

Wypróbuj to obejście problemu z motywami:

@Override
public void onBackPressed() {
    NavUtils.navigateUpTo(this, new Intent(this,
            MyNeedToBeRefreshed.class));
}

3
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);

Pozwala to na ponowne załadowanie ze zmianami motywu i ukrycie animacji.


3

Miałem również ten problem, ale podążając za przykładem Farhana dotyczącym używania setContentView(), zrobiłem to. setContentView()Samo używanie nie wystarczyło. Stwierdziłem, że muszę ponownie wypełnić wszystkie swoje poglądy informacjami. Aby to naprawić, po prostu wyciągnąłem cały kod do innej metody (nazwałem to budowaniem), aw mojej onCreatemetodzie po prostu wywołuję tę kompilację. Teraz za każdym razem, gdy pojawia się moje zdarzenie, w którym chcę, aby moja aktywność się „odświeżyła”, po prostu wywołuję build, podaję nowe informacje (które przekazuję jako parametry do zbudowania) i mam odświeżoną aktywność.


2

Wygląda na to, że jest to znany błąd .


setTheme działa znaleźć, kiedy ponownie uruchomię moją aktywność (wywołanie finish (), a następnie startActivity ()). Po prostu nie mogę odświeżyć motywu bez ponownego uruchomienia mojej aktywności ...
MickeyR

0

Nie wiem, czy to jest bezpieczne, czy nie, ale zadziałało. Jakbym wpadł na ten problem i sam spróbował invalidate()i requestLayout()ale bezskutecznie. Więc po prostu ponownie zadzwoniłem onCreate(null)i zadziałało. Jeśli jest to niebezpieczne, daj mi znać. Mam nadzieję, że to komuś pomoże.


Ustawiasz wartość saveInstanceState na wartość null, co może spowodować nieoczekiwane zachowanie. Więcej informacji: stackoverflow.com/questions/15115975/…
PhilipB

0

W ten sposób odświeżyłem mój układ

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

0

Aby wyczyścić widok rozszerzający ViewGroup, wystarczy użyć metody removeAllViews()

Tak po prostu (jeśli masz nazwę ViewGroup myElement):

myElement.removeAllViews()


-1

Nie jestem pewien, czy to dobre podejście, ale za każdym razem dzwonię do tego:

setContentView(R.layout.mainscreen);

-8

Po prostu wywołaj działanie ponownie, używając intencji. Na przykład, aby odświeżyć układ MainActivity, wykonaj następujące czynności:

startActivity(new Intent(MainActivity.this, MainActivity.class));

2
To brzydkie! Kiedy to robisz, po prostu dodajesz nową aktywność na stosie, więc po naciśnięciu przycisku Wstecz wrócisz do tej samej czynności.
Daniel Beltrami
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.