Как заставить весь макет обновить представление?

173

Я хочу заставить перерисовывать / обновлять основной вид ресурсов макета, скажем, методом Activity.onResume (). Как я могу это сделать ?

Под основным представлением макета я имею в виду тот («R.layout.mainscreen» ниже), который вызывается в моем Activity.onCreate (), например:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mainscreen);
}
MickeyR
источник
Вы пытались присвоить имя включающему Linear / Relative / WheverLayout, вызвать для него findViewById, а затем вызвать invalidate () для этого? (Я бы назвал это ответом, но я не знаю, признают ли родители-инвалиды детей недействительными, и я не где-то, где я могу это проверить.)
Бен Уильямс
Спасибо также ! Я все еще борюсь с этим все же. Можете ли вы взглянуть на то, что я опубликовал ниже. Мне нужен этот код (или другой?), Чтобы обновить мою тему ...
MickeyR

Ответы:

149

Чтобы строго ответить на вопрос: используйте invalidate ():

public void invalidate () Начиная с: Уровень API 1

Опровергнуть весь взгляд. Если представление является видимым, onDraw (Canvas) будет вызван в какой-то момент в будущем. Это должно быть вызвано из потока пользовательского интерфейса. Для вызова из не-пользовательского интерфейса вызовите postInvalidate ().

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

Теперь, когда действие возобновляется, он заставляет каждый вид рисовать сам. Не нужно вызывать invalidate (). Чтобы применить тему, убедитесь, что вы делаете это до того, как будет нарисовано любое представление, т.е.setContentView(R.layout.mainscreen);

public void setTheme (int остаток) С: API Уровень 1

Установите базовую тему для этого контекста. Обратите внимание, что это следует вызывать до того, как будут созданы какие-либо представления в контексте (например, перед вызовом setContentView (View) или inflate (int, ViewGroup)).

Ссылка на документацию по API находится здесь: http://developer.android.com/reference/android/view/ContextThemeWrapper.html#setTheme%28int%29

Поскольку метод onDraw () работает с уже созданными экземплярами Views, setTheme работать не будет. У меня нет опыта работы с темами, но я могу подумать о двух альтернативных вариантах:

  1. вместо этого вызовите setTheme в onCreate (), или
  2. повторить setContentView (R.layout.mainscreen); заставить восстановить все макет.
Aleadam
источник
Спасибо ! Это работает хорошо, но я не вижу, что я ожидал. Непосредственно перед запуском вашего кода я запускаю Activity.setTheme (newtheme), но этот вызов invalidate () не приводит к изменению темы (например, с Dark на Light). Должен ли invalidate () это сделать?
MickeyR
@MickeyR нет, не должно. Проверьте мой обновленный ответ. Если эти две опции не работают, вам нужно будет перезапустить свою активность.
Алеадам
Вариант (1) работает. Мое приложение запустится с правильной темой, но если я изменю ее во время работы, мне придется перезапустить приложение, чтобы снова вызывать onCreate ().
MickeyR
Вариант (2) - это маршрут, который я хотел выбрать. Итак, когда тема изменяется во время работы, я хотел, чтобы onRestart () сделал это: - setTheme (getPreferenceTheme ()); и setContentView (R.layout.main); Но это не меняет мою тему. Я не могу заставить этот второй вариант работать ...?!
MickeyR
Я понял, что для работы опции (2) мне нужно «заново раздувать иерархию представлений». Я пробовал разные вещи, чтобы достичь этого, но я не совсем уверен, что это значит, и как это сделать.
MickeyR
41

Пытаться getWindow().getDecorView().findViewById(android.R.id.content).invalidate();

keyboardsurfer
источник
3
Спасибо ! Тот же ответ, который я написал выше для Алеадама. Этот invalidate () не вызывает обновление темы активности, что мне и нужно.
MickeyR
36

Попробуйте, recreate()это приведет к воссозданию этого занятия.

Моханад АЛХУЛИ
источник
4
Я перепробовал все варианты в этой теме, и это единственный, который работал с наименьшими нежелательными побочными эффектами.
swooby
1
Что делать, если мне нужно это сделать в onResumeметоде. Это дает мне бесконечный цикл: /
Камил Витковски
Ну, я не рекомендую использовать его, пока вам действительно не нужно. Вы можете сохранить флаг в общих настройках, чтобы избежать бесконечного цикла.
Моханад АЛХОУЛИ
это работает, но я бы не рекомендовал использовать его в реальном режиме работы приложения. Мне он нужен только для режима отладки, поэтому побочный эффект обновления всего пользовательского интерфейса не является критическим.
drorsun
31

Решение:

Ребята, я перепробовал все ваши Решения, но они не сработали для меня, я должен установить для setVisibility EditText значение VISIBLE, и этот EditText должен быть виден тогда в ScrollView , но я не смог обновить представление root для вступления в силу. Я решил свою проблему, когда мне нужно обновить вид, поэтому я изменил видимость ScrollView на GONE, а затем снова установил его на VISIBLE, чтобы он вступил в силу, и это сработало для меня. Это не точное решение, но оно только сработало.

 private void refreshView(){
    mScrollView.setVisibility(View.GONE);
    mScrollView.setVisibility(View.VISIBLE);
}
Навид Ахмад
источник
2
@MickeyR Пожалуйста, примите ответ, чтобы люди могли легко найти решение
Навид Ахмад
вау .. Я также попробовал все предложенные решения, но это, кажется, работает только один, но это немного ужасно ...
Рик ван Велзен
Я не знаю, почему @MickeyR не принимает этот ответ
Навид Ахмад
1
@NaveedAhmad Спасибо! После 4 часов работы, которые я мог сделать, это было единственным решением, которое сработало.
Codelicious
10

Вызов invalidate()или postInvalidate()корневой макет явно НЕ гарантирует, что дочерние представления будут перерисованы. В моем конкретном случае мой корневой макет был TableLayout и имел несколько дочерних классов класса TableRow и TextView. Вызов postInvalidate(), или requestLayout()даже forceLayout()на корневой объект TableLayout не вызывает никаких TextViews в макете , чтобы быть перерисованы.

Итак, в итоге я рекурсивно проанализировал макет, ища эти TextViews, а затем вызвал postInvalidate()каждый из этих объектов TextView.

Код можно найти на GitHub: https://github.com/jkincali/Android-LinearLayout-Parser

jkincali
источник
9

В противном случае вы можете попробовать это также

ViewGroup vg = (ViewGroup) findViewById (R.id.videoTitleTxtView);
 vg.removeAllViews();
 vg.refreshDrawableState();
Датта Кунде
источник
4
Спасибо за это ! Но это удалило все просмотры, которые у меня были (TextView, кнопки и т. Д.), Но не перерисовал их - мой экран остался пустым ...
MickeyR
вам нужно обновить вид, а затем снова вызвать функцию рисования. после очистки предыдущего вида.
Датта Кунде
4

Просто установите ваш контент в onresume

setContentView (R.layout.yourview) внутри onResume ..

Пример:

@Override
public void onResume(){
super.onResume();
setContentView(R.layout.activity_main); 
postIncomeTotals();
}
Фархан
источник
Привет, я попробовал это, и те же данные в списке просмотра вытягиваются дважды, следовательно, если у меня было 4 строки, и обновление должно было добавить пятую строку, вместо этого я получаю 10, а затем 15, ... что делать?
iOSAndroidWindowsMobileAppsDev
4

Попробуйте обойти эту проблему:

@Override
public void onBackPressed() {
    NavUtils.navigateUpTo(this, new Intent(this,
            MyNeedToBeRefreshed.class));
}
Krilivye
источник
3
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);

Это позволяет перезагрузить с изменениями темы и скрывает анимацию.

Codeversed
источник
3

У меня тоже была эта проблема, но, следуя указаниям Фархана по использованию, setContentView()я сделал именно это. использование setContentView()само по себе было недостаточно, однако. Я обнаружил, что должен был заселить все свои взгляды информацией. Чтобы исправить это, я просто вытянул весь этот код в другой метод (я назвал его сборкой), а в своем onCreateметоде я просто вызвал эту сборку. Теперь, когда происходит мое событие, я хочу, чтобы моя деятельность «обновлялась», я просто вызываю сборку, сообщаю ему новую информацию (которую я передаю в качестве параметров для сборки), и у меня появляется обновленное действие.

user3612162
источник
2

Это похоже на известную ошибку .

Бен Уильямс
источник
setTheme работает найти, когда я перезапускаю свою деятельность (вызову finish () и затем startActivity ()). Я просто не могу заставить его обновить тему, не возобновляя свою деятельность ...
MickeyR
0

Я не знаю, безопасно это или нет, но это сработало для меня. Я вроде столкнулся с этой проблемой я и попытался invalidate()и , requestLayout()но безрезультатно. Так что я просто onCreate(null)перезвонил, и это сработало. Если это небезопасно, пожалуйста, дайте мне знать. Надеюсь, это поможет кому-то там.

Cai
источник
Вы устанавливаете для saveInstanceState значение null, что может вызвать непредвиденное поведение. Для получения дополнительной информации: stackoverflow.com/questions/15115975/…
PhilipB
0

Так я обновлял свой макет

Intent intent = getIntent();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);
sivaBE35
источник
0

Чтобы очистить представление, расширяющее ViewGroup, вам просто нужно использовать метод removeAllViews()

Так же, как это (если у вас есть ViewGroup называется myElement):

myElement.removeAllViews()
Разъем'
источник
0

Попробуй это

view.requestLayout();
Милинд Чаудхари
источник
-1

Не уверен, что это хороший подход, но я просто каждый раз так называю:

setContentView(R.layout.mainscreen);
Кшиштоф Ткач
источник
-8

Просто снова вызовите действие, используя намерение. Например, чтобы обновить макет MainActivity, сделайте так:

startActivity(new Intent(MainActivity.this, MainActivity.class));
Аншул Аггарвал
источник
2
Это безобразно! Когда вы делаете это, вы просто добавляете новое действие в стек, поэтому, когда вы нажимаете кнопку «Назад», вы возвращаетесь к тому же действию.
Даниэль Бельтрами