4

この質問はさまざまな形で何度か聞かれましたが、明確な答えは見つかりませんでした。

Viewsコンテナの初期レイアウト(a)の後で、子孫の寸法と位置を取得できる必要がありますcontentView。この場合に必要な寸法は、予測できないビュー(グループ)です。複数行のテキスト、装飾に対応するための最小の高さなどがある場合があります。すべてのレイアウトパス()ですべてを実行する必要はありませんonLayout。私が必要とする測定値は、深くネストされた子からのものであるため、間にある各コンテナーのonLayout/をオーバーライドすることは適切ではないようです。onMeasureループ(trigger-event-during-event)を引き起こすようなことは何もしません。

Romain Guyはかつて、.postaRunnableのコンストラクターView(AFAIKはUIスレッドに含まれる)でのみ可能であるとほのめかしました。これはほとんどのデバイス(私が個人的に持っている4つのうち3つ)で機能するようですが、Nexus Sでは失敗します。NexusSは、子供ごとに1回パスするまで、すべてのサイズがなく、正しいサイズではないようです。postedRunnablerunメソッドが呼び出されたとき。レイアウトパス(in onLayout)を数えて、と比較してみましたgetChildCount。これも4つのうち3つで機能しますが、別の3つ(Droid Razrでは失敗します。DroidRazrは1回のパスで失敗し、すべての測定値を取得します)は、子の数に関係ありません。 )。上記のさまざまな順列を試しました(通常の投稿、への投稿、へのHandlerキャストgetContext()Activityそして呼び出しrunOnUiThreadます...すべてに対して同じ結果)。

ターゲットグループの高さを親の高さと照合することで、恐ろしい恥ずべきダメハックを使用することになりました。異なる場合は、レイアウトされていることを意味します。明らかに、最善のアプローチではありませんが、さまざまなデバイスと実装の間で確実に機能するように見える唯一のアプローチです。使用できる組み込みのイベントやコールバックがないことは知っていますが、もっと良い方法はありますか?

TYIA

/ EDIT私にとっての結論は、私がテストした他のすべてのデバイスの場合と同様に、Romain Guyや他の人が示唆しているように、NexusSはレイアウトが完了.posting()するまで待機しないということです。Runnable良い回避策は見つかりませんでした。ありますか?

4

2 に答える 2

9

OnGlobalLayoutListenerの使用に成功しました。

それは私のネクサスSでうまくいきました

final LinearLayout marker = (LinearLayout) findViewById(R.id.distance_marker);
OnGlobalLayoutListener listener = new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        //some code using marker.getHeight(), etc.
        markersContainer.getViewTreeObserver().removeGlobalOnLayoutListener(this);
    }
};
marker.getViewTreeObserver().addOnGlobalLayoutListener(listener);
于 2012-12-19T01:26:46.497 に答える
3

OnGlobalLayoutListenerでの私自身の経験では、すべての子ビューがレイアウトされるまで、起動を常に待機するとは限りません。したがって、特定の子(または子の子など)ビューのディメンションを探している場合、onGlobalLayout()メソッド内でそれらをテストすると、レイアウトの中間状態を反映していることがわかります。プロセスであり、ユーザーに表示される最終(静止)状態ではありません。

これをテストしたところ、postDelayed()を1秒の遅延で実行することで(明らかに競合状態ですが、これはテスト用でした)、正しい値を取得したことに気付きました(子ビューの子の場合)が、遅延なしで単純なpost()を実行した場合、間違った値を取得しました。

私の解決策は、OnGlobalLayoutListenerを回避し、代わりにトップレベルビュー(子を測定する必要のある子を含むビュー)でdispatchDraw()の直接オーバーライドを使用することでした。デフォルトのdispatchDraw()は、現在のビューのすべての子ビューを描画するため、dispatchDraw()内でsuper.dispatchDraw(canvas)を呼び出した後に測定を実行するコードへの呼び出しを投稿すると、すべての子が確実になります。測定を行う前にビューが描画されます。

これは次のようになります。

@Override
protected void dispatchDraw(Canvas canvas) {
  //Draw the child views
  super.dispatchDraw(canvas);

  //All child views should have been drawn now, so we should be able to take measurements
  // of the global layout here
  post(new Runnable() {
    @Override
    public void run() {
      testAndRespondToChildViewMeasurements();
    }
  });
}

もちろん、これらの測定を行う前に描画が行われるため、それを防ぐには遅すぎます。しかし、それが問題ではない場合、このアプローチは、子孫ビューの最終的な(静止した)測定値を非常に確実に提供するようです。

必要な測定値を取得したら、testAndRespondToChildViewMeasurements()の上部にフラグを設定して、それ以上何もせずに戻るようにします(または、dispatchDraw()内で同様のテストを実行してそれ自体をオーバーライドします)。 OnGlobalLayoutListenerとは異なり、このオーバーライドを削除する方法はありません。

于 2014-01-20T10:52:08.643 に答える