レイアウトビュー全体を強制的に更新する方法は?


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

回答:


149

質問に厳密に答えるには、invalidate()を使用します。

public void invalidate()以降:APIレベル1

ビュー全体を無効にします。ビューが表示されている場合、onDraw(Canvas)は将来のある時点で呼び出されます。これは、UIスレッドから呼び出す必要があります。非UIスレッドから呼び出すには、postInvalidate()を呼び出します。

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

これで、アクティビティが再開すると、すべてのビューが自分自身を描画するようになります。invalidate()を呼び出す必要はありません。テーマを適用するには、ビューが描画される前、つまり、setContentView(R.layout.mainscreen);

public void setTheme(int resid)以降:APIレベル1

このコンテキストの基本テーマを設定します。これは、ビューがコンテキストでインスタンス化される前に(たとえば、setContentView(View)またはinflate(int、ViewGroup)を呼び出す前に)呼び出す必要があることに注意してください。

APIドキュメントリファレンスはこちら:http : //developer.android.com/reference/android/view/ContextThemeWrapper.html#setTheme%28int%29

onDraw()メソッドはすでにインスタンス化されたビューで機能するため、setThemeは機能しません。私自身はテーマについての経験はありませんが、考えられる2つの代替オプションは次のとおりです。

  1. 代わりにonCreate()でsetThemeを呼び出します。
  2. redo setContentView(R.layout.mainscreen); すべてのレイアウトを強制的に再インスタンス化します。

よろしくお願いします!これは正常に実行されますが、期待したとおりに表示されません。コードを実行する直前に、Activity.setTheme(newtheme)を実行しますが、このinvalidate()呼び出しによってテーマが変更されることはありません(たとえば、DarkからLightへ)。invalidate()はそれを行うことができますか?
MickeyR

@MickeyRいいえ、それはすべきではありません。私の更新された答えを確認してください。これらの2つのオプションが機能しない場合は、アクティビティを再起動する必要があります。
Aleadam、

オプション(1)は機能します。アプリは正しいテーマで起動しますが、実行中に変更した場合は、onCreate()が再度呼び出されるようにアプリを再起動する必要があります。
MickeyR、

オプション(2)は、私が取りたかったルートです。したがって、実行中にテーマが変更されたときに、onRestart()でこれを実行する必要がありました。-setTheme(getPreferenceTheme()); およびsetContentView(R.layout.main); しかし、これは私のテーマを変更しません。この2番目のオプションが機能しない...?!
MickeyR、

オプション(2)を機能させるには、「ビュー階層を再度インフレート」する必要があることを理解しました。私はこれを達成するためにさまざまなことを試みましたが、これが何を意味するのか、これをどのように行うのか本当にわかりません。
MickeyR、

41

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


3
よろしくお願いします!上記の回答をAleadamに投稿しました。このinvalidate()は、私が必要とするアクティビティテーマを更新しません。
MickeyR、

36

recreate()このアクティビティが再作成されるようにしてみてください。


4
私はこのスレッドのすべてのオプションを試しましたが、これは望ましくない副作用を最小限に抑えて機能した唯一のオプションです。
スウビー、2015

1
onResumeメソッドでこれを行う必要がある場合はどうなりますか?これは私に無限ループを与えます:/
Kamil Witkowski

まあ、私は本当に必要になるまでそれを使用することをお勧めしません。無限ループを回避するために、共有設定にいくつかのフラグを保存できます。
Mohanad ALKHOULI

これは機能しますが、実際のプロダクションモードアプリで使用することはお勧めしません。デバッグモードでのみ必要だったので、UI全体の更新による副作用は重要ではありません。
drorsun 2018

31

解決:

みんな私はあなたのソリューションのすべてを試みたが、彼らは私のために働いていなかった、私が設定する必要がsetVisibilityへのEditTextのVISIBLE、これのEditTextはで、その後表示されている必要がありScrollViewが、私を有効にするには、ルートビューをリフレッシュすることができませんでした。ビューを更新する必要があるときに問題を解決したので、ScrollViewの可視性をGONEに変更してから、再度VISIBLEに設定して有効にしました。これは正確な解決策ではありませんが、うまくいきました。

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

2
@MickeyR答えを受け入れて、人々が簡単に解決策を見つけられるようにしてください
Naveed Ahmad

すごい..提案されたすべての解決策も試しましたが、これが唯一の解決策であるように見えますが、それは恐ろしいことです...
Rik van Velzen

@MickeyRがこの回答を受け入れない理由がわかりません
Naveed Ahmad、2018

1
@NaveedAhmadありがとうございます!私ができることすべてを4時間行った後、これが機能する唯一のソリューションでした。
Codelicious

10

を呼び出すinvalidate()postInvalidate()、ルートレイアウトを使用しても、子ビューが再描画されることは保証されません。私の特定のケースでは、ルートレイアウトはTableLayoutであり、TableRowクラスとTextViewクラスのいくつかの子がありました。ルートTableLayoutオブジェクトを呼び出しpostInvalidate()たりrequestLayout()、呼び出したりしてもforceLayout()、レイアウト内の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、ボタンなど)は削除されましたが、再描画されませんでした-画面に何も表示されませんでした...
MickeyR

ビューを正しく更新してから、draw関数を再度呼び出す必要があります。前のビューをクリーニングした後。
Datta Kunde、

4

onresumeでコンテンツビューを設定するだけです

onResume内のsetContentView(R.layout.yourview)

例:

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

こんにちは私はこれを試して、リストビューの同じデータが2回プルされたので、4行があり、更新によって5行が追加されるはずだった場合、代わりに10、15、...とどうなりますか?
iOSAndroidWindowsMo​​bileAppsDev 2016

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()、それ自体では、しかし、十分ではありませんでした。すべての見解に情報を再入力する必要があることがわかりました。これを修正するには、すべてのコードを別のメソッド(私はそれをビルドと呼びます)にプルし、私のonCreateメソッドではそのビルドを呼び出します。イベントが発生してアクティビティを「更新」したいときはいつでも、buildを呼び出して新しい情報(ビルドのパラメーターとして渡す)を渡すだけで、更新されたアクティビティを取得できます。



0

これが安全かどうかはわかりませんが、うまくいきました。私はちょっとこの問題に自分自身を実行してみましたinvalidate()し、requestLayout()しかし無駄に。だから私onCreate(null)はもう一度自分に電話をかけただけでうまくいきました。これが安全でない場合は、私に知らせてください。これが誰かを助けることを願っています。


savedInstanceStateを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
それは醜いです!これを行うと、新しいアクティビティをスタックに追加するだけなので、戻るボタンを押すと、同じアクティビティに戻ります。
Daniel Beltrami、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.