forceLayout()、requestLayout()、およびinvalidate()の使用


185

私はの役割について混乱少しだforceLayout()requestLayout()invalidate()のメソッドViewクラス。

いつ呼び出されますか?

回答:


357

FrançoisBOURLIEUXDalvikによって提供された回答をよりよく理解するには、Arpit Mathurによるこの素晴らしいビューライフサイクル図をご覧になることをお勧めします。 ここに画像の説明を入力してください


28
無効化が呼び出された直後にrequestLayoutが呼び出されることがよくあります。TextViewなどのAndroidソースコードで発生することさえありますが、この図によると、そうすることは冗長です。それを行う目的はありますか?
tcox

5
それは興味深い質問です。正直に言うと、なぜで両方のメソッドを呼び出すのかわかりませんTextView。私は多分、彼らが描きたいと思ったView彼らはそのレイアウト関連のパラメータを変更する前に、最後の時間のために、私たちは異なる順序(に呼び出されて、それらの呼び出しを考えるならば、それは実際にどんな意味がないと、彼らは呼び出しinvalidate()直後requestLayout()TextView同じように)。多分それはStackOverflowで別の質問に値するでしょう:)?
Bartek Lipinski

14
(1/2):この2つの方法(invalidate()requestLayout())を正しく理解していないと思います。これらのメソッドの目的は、(無効化と呼ばれた)Viewどのような無効化が発生したかを通知することです。Viewこれらのメソッドの1つを呼び出した後に、がどのパスをたどるかを決定するようなものではありません。View-lifecycle-pathの選択の背後にあるロジックは、それ自体を呼び出す適切なメソッドを選択することです。サイズ変更に関連するものがある場合requestLayout()-呼び出す必要がありますinvalidate()。サイズ変更なしで視覚的な変更のみがある場合-を呼び出す必要があります。
Bartek Lipinski 2016年

11
(2/2):あなたのサイズを変更する場合はView、いくつかの方法で、例えばあなたは、現在の取得LayoutParamsView、あなたがそれらを変更、しかし、NOTのいずれかを呼び出すrequestLayoutsetLayoutParams(呼び出すrequestLayoutあなたが呼び出すことができ、内部的に)invalidate()あなたが好きな限り、及びこれViewはメジャーレイアウトプロセスを通過しないため、そのサイズは変更されません。あなたが教えていない場合はViewその大きさが(と変化していることrequestLayoutメソッドの呼び出し)、そしてViewそれがなかったと仮定しますと、onMeasureonLayout呼ばれることはありません。
Bartek Lipinski 2016年

2
もっとここ@tcox - > stackoverflow.com/questions/35279374/...
Sotti

125

invalidate()

invalidate()ビューの再描画をスケジュールしたいときに呼び出しが行われます。それはonDraw(ただし、すぐに、すぐに)最終的に呼び出されています。カスタムビューが呼び出すのは、テキストまたは背景色のプロパティが変更されたときです。

ビューは再描画されますが、サイズは変更されません。

requestLayout()

サイズに影響を与えるビューの変更がある場合は、を呼び出す必要がありますrequestLayout()。これがトリガーされonMeasureonLayout、親ビューのために、このビューのためではなく、すべての方法のラインアップだけではなく。

呼び出しrequestLayout()結果としてonDraw(受け入れられた回答の図が意味するものとは逆に)になることが保証されていないため、通常はと組み合わされinvalidate()ます。

invalidate();
requestLayout();

この例は、カスタムラベルのテキストプロパティが変更された場合です。ラベルのサイズが変わるため、再測定して再描画する必要があります。

forceLayout()

requestLayout()親ビューグループで呼び出されるがある場合、その子ビューを再測定して再レイアウトする必要はありません。ただし、子供を再測定と再レイアウトに含める必要がある場合は、子供を呼び出すことができますforceLayout()。直接の親forceLayout()と一緒に発生した場合にのみ、子で機能しrequestLayout()ます。ビューツリーのアップをforceLayout()トリガーしないため、それ自体を呼び出しても効果はありませんrequestLayout()

の詳細については、このQ&Aをご覧くださいforceLayout()

さらなる研究


1
しかし、最初にrequestLayout()を呼び出し、次にinvalidate()を呼び出す方が理にかなっているのではないでしょうか。
ショルト

2
@scholt、私が知る限り、順序は問題ではないので、必要に応じてrequestLayout()前に呼び出すことができますinvalidate()。どちらもすぐにレイアウトや描画を行いません。むしろ、最終的に再レイアウトと再描画をもたらすフラグを設定します。
Suragch

27

ここにいくつかの応答があります:http : //developer.android.com/guide/topics/ui/how-android-draws.html

私にとってはinvalidate()、ビューをrequestLayout()更新するための呼び出しと、ビューを更新するための呼び出しと、画面上のビューのサイズを計算します。


3
次に、forceLayout()はどうですか?
sdabet

@fiddler、このメソッドは2つのフラグを設定するだけです:PFLAG_FORCE_LAYOUTおよびPFLAG_INVALIDATED
Suitianshi

7
@suitianshiでは、フラグを設定するとどうなりますか?
セルゲイ、

1
@Sergey結果として、このフラグはメジャーキャッシュをオーバーライドするようです(ビューは、同じMeasureSpecについて、将来キャッシュを使用してより高速に測定します)。ここView.javaのライン18783を参照してください。github.com/android/platform_frameworks_base/blob/master/core/...
RhetoricalRuvim

3

再描画するビューでinvalidate()を使用すると、onDraw(Canvas c)が呼び出され、requestLayout()によってレイアウトレンダリング全体(測定フェーズと配置フェーズ)が再度実行されます。実行時に子ビューのサイズを変更する場合、ただし親ビューからの制約のような特定の場合にのみ使用する必要があります(つまり、親の高さまたは幅がWRAP_CONTENTであるため、子を再度ラップする前に一致を測定します)


3

この答えは正しくありませんforceLayout()

あなたがのコードで見ることができるようにforceLayout()ビューに「再レイアウトが必要」とマークされているだけで、再レイアウトのスケジュールやトリガーは行われていません。再レイアウトは、将来のある時点で、ビューの親が他の何らかの理由で配置されるまで発生しません。

forceLayout()and を使用する場合には、さらに大きな問題がありrequestLayout()ます。

forceLayout()ビューを呼び出したとしましょう。requestLayout()このビューの子孫を呼び出すと、AndroidはrequestLayout()その子孫の祖先を再帰的に呼び出します。問題は、呼び出したビューで再帰が停止することですforceLayout()そのため、requestLayout()呼び出しがビュールートに到達することはなく、レイアウトパスをスケジュールすることもありません。ビュー階層のサブツリー全体がレイアウトを待機しておりrequestLayout()、そのサブツリーのビューを呼び出してもレイアウトは発生しません。requestLayout()そのサブツリーの外側のビューを呼び出すだけで、魔法が解かれます。

私はの実装を検討しますforceLayout()(そしてそれrequestLayout()が壊れるのにどのように影響するか、そしてあなたはコードでその関数を決して使用すべきではありません)。


1
こんにちは!どのようにしてその呪文を思いついたのですか?それはどこかに文書化されていますか?
アジズベキアン2017年

1
残念ながら、それは文書化されておらず、おそらく意図もされていません。私は、コードを調査し、View自分で問題を実行してデバッグすることで、それを理解しました。
fluidsonic 2017年

それから私は、の目的について興味forceLayout()API:それは実際にレイアウトパスを強制しない、むしろそれだけでフラグ変更で観察されているonMeasure()が、onMeasure()いない限り呼ばれませんrequestLayout()か、明示的にView#measure()呼ばれています。つまり、forceLayout()とペアにする必要がありrequestLayout()ます。一方、forceLayout()まだ実行する必要があるのに、なぜそれを実行するのrequestLayout()ですか?
アジズベキアン2017年

@azizbekianいいえ、する必要はありません。requestLayout()も行うすべてをforceLayout()行います。
fluidsonic 2017年

1
@Suragchはその1つを逃した、ありがとう!非常に興味深い分析。の使用目的forceLayoutは理にかなっています。つまり、結局のところ、非常にひどい名前が付けられ、文書化されています。
fluidsonic '20年

0

invalidate()---> onDraw()UIスレッドから

postInvalidate()---> onDraw()バックグラウンドスレッドから

requestLayout()---> onMeasure()およびonLayout()ANDでなくてもかまいません onDraw()

  • 重要:このメソッドを呼び出しても、呼び出されたクラスの子には影響しません。

forceLayout()---> onMeasure()onLayout() 場合は、単に直接の親と呼ばれますrequestLayout()

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.