如何强制整个布局视图刷新?


173

我想强迫主布局资源视图重绘/刷新,例如Activity.onResume()方法。我怎样才能做到这一点 ?

通过主布局视图,我的意思是在Activity.onCreate()中调用的那个(下面的“ R.layout.mainscreen”),如下所示:-

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

您是否尝试过命名封闭的Linear / Relative / WhateverLayout,在其上调用findViewById,然后在其上调用invalidate()?(我想以此作为答案,但我不知道使父母作废的父母是否也会使孩子也作废,而且我不在可以测试的地方。)
本·威廉姆斯

还要感谢 !我仍然在为此挣扎。您能看看我在下面发布的内容吗?我需要此代码(或其他代码)来使主题刷新...
MickeyR 2011年

Answers:


149

要严格回答这个问题:使用invalidate():

public void invalidate()从:API级别1

使整个视图无效。如果该视图可见,则将来会在某个时候调用onDraw(Canvas)。必须从UI线程调用它。要从非UI线程进行调用,请调用postInvalidate()。

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

现在,当Activity恢复时,它将使每个视图都可以绘制。不需要调用invalidate()。要应用主题,请确保在绘制任何视图之前(即在setContentView(R.layout.mainscreen);

公共无效setTheme(int resid)从:API级别1

设置此上下文的基本主题。请注意,应在Context中实例化任何视图之前(例如,在调用setContentView(View)或inflate(int,ViewGroup)之前)调用此方法。

API文档参考位于此处:http : //developer.android.com/reference/android/view/ContextThemeWrapper.html#setTheme%28int%29

由于onDraw()方法适用于已实例化的View,因此setTheme将不起作用。我自己没有主题的经验,但是我可以想到的两个选择是:

  1. 而是在onCreate()中调用setTheme,或者
  2. 重做setContentView(R.layout.mainscreen); 强制实例化所有布局。

谢谢 !一切正常,但是我没有看到预期的结果。就在运行您的代码之前,我运行Activity.setTheme(newtheme),但是此invalidate()调用不会导致主题发生更改(例如,从暗到亮)。invalidate()应该能够做到这一点吗?
MickeyR 2011年

@MickeyR不,不应该。检查我更新的答案。如果这两个选项不起作用,则您将需要重新启动活动。
阿莱丹2011年

选项(1)起作用。我的应用程序将以正确的主题开头,但是如果我在运行时更改主题,则必须重新启动我的应用程序,以便再次调用onCreate()。
MickeyR 2011年

选项(2)是我要走的路线。因此,当主题在运行时更改时,我希望onRestart()做到这一点:-setTheme(getPreferenceTheme()); 和setContentView(R.layout.main); 但这并没有改变我的主题。我无法让第二个选项起作用...?!
MickeyR 2011年

我知道要使选项(2)正常工作,我需要“重新为视图层次结构添加”。我已经尝试了不同的方法来实现这一目标,但是我不确定这意味着什么,也不确定如何做到这一点。
MickeyR 2011年

41

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


3
谢谢 !我在上方发布给Aleadam的答案相同。此invalidate()不会导致活动主题刷新,这正是我需要的。
MickeyR 2011年

36

尝试recreate()它将导致重新创建此活动。


4
我尝试了该线程中的所有选项,这是唯一产生最少不良副作用的选项。
swooby 2015年

1
如果我需要这样做在onResume方法中怎么办。这给了我无限循环:/
卡米尔·

好吧,我不建议您真正使用它之前。您可以在共享首选项中保存一些标志,以避免无限循环。
Mohanad ALKHOULI

这可行,但我不建议在实际生产模式应用程序中使用它。我仅在调试模式下需要它,因此整个UI刷新的副作用并不重要。
drorsun

31

解:

伙计们,我尝试了所有的解决方案,但对我没有用,我必须将EditText的setVisibility设置为VISIBLE,然后在ScrollView中应该可以看到此EditText ,但是我无法刷新根视图才能生效。当需要刷新视图时,我解决了问题,因此将ScrollView可见性更改为GONE,然后再次将其设置为VISIBLE才能生效,并且对我有用。这不是确切的解决方案,但只能解决问题。

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

2
@MickeyR请接受答案,以便人们可以轻松找到解决方案
Naveed Ahmad

哇..我也尝试了所有建议的解决方案,但这似乎是唯一可行的解​​决方案,但这有点可怕...
Rik van Velzen

我不知道为什么@MickeyR不接受此答案
Naveed Ahmad

1
@NaveedAhmad谢谢!经过4个小时的全力以赴,这是唯一有效的解决方案。
Codelicious

10

在根布局上调用invalidate()postInvalidate()显然不能保证将重绘子视图。在我的特定情况下,我的根布局是TableLayout,并且具有TableRow和TextView类的几个子级。调用postInvalidate()requestLayout()甚至调用forceLayout()根TableLayout对象,都不会导致重新绘制布局中的任何TextView。

因此,我最终要做的是递归地解析布局以查找那些TextView,然后调用postInvalidate()每个TextView对象。

该代码可以在GitHub上找到:https : //github.com/jkincali/Android-LinearLayout-Parser


9

否则,您也可以尝试以下操作-

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

4
谢谢你!但是,这删除了我所有的视图(TextView,Buttons等),但没有重新绘制它们-我的屏幕仍然空白...
MickeyR 2011年

您需要正确刷新视图,然后需要再次调用draw函数。清洁上一个视图之后。
达塔·昆德

4

只需将您的内容视图设置为onresume

在onResume中的setContentView(R.layout.yourview)。

例:

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

嗨,我尝试过此操作,并且将listview中的相同数据提取了两次,因此,如果我有4行,而刷新应该添加第五行,那么我最终得到10行,然后是15行,...该怎么办?
iOSAndroidWindowsMo​​bileAppsDev

4

请尝试以下解决方法来解决主题问题:

@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);

这使您可以重新加载主题更改并隐藏动画。


3

我也遇到了这个问题,但是在Farhan的使用指导下,setContentView()我做到了。setContentView()但是,仅靠使用本身是不够的。我发现我必须用信息重新填充所有观点。为了解决这个问题,我只是将所有代码都拉到了另一个方法(我称之为build)中,而在我的onCreate方法中,我只是调用了该build。现在,每当发生事件时,只要我希望我的活动“刷新”,我就调用build,为其提供新信息(我将其作为要传递的参数传递给build),并且我有了一个刷新的活动。



0

我不知道这是否安全,但对我有用。我自己碰到了这个问题,尝试了一下invalidate()requestLayout()但无济于事。所以我onCreate(null)再次打电话给我,一切都奏效了。如果这样做不安全,请告诉我。希望这可以帮助某人。


您正在将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);

0

要清除扩展ViewGroup的视图,您只需要使用方法 removeAllViews()

就像这样(如果您有一个名为的ViewGroup myElement):

myElement.removeAllViews()



-8

只需使用意图再次调用活动本身即可。例如,要刷新MainActivity的布局,请执行以下操作:

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

2
太丑了!执行此操作时,您只需在堆栈上添加一个新活动,因此,当您按下返回按钮时,您将返回到同一活动。
丹尼尔·贝特拉米
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.