web-dev-qa-db-ja.com

ビューの寸法を取得する方法は?

TableLayout, TableRow and TextViewで構成されるビューがあります。グリッドのように見せたい。このグリッドの高さと幅を取得する必要があります。メソッドgetHeight()およびgetWidth()は常に0を返します。これは、グリッドを動的にフォーマットするとき、およびXMLバージョンを使用するときに発生します。

ビューのディメンションを取得する方法は?


以下は、デバッグで結果を確認するために使用したテストプログラムです。

import Android.app.Activity;
import Android.os.Bundle;
import Android.widget.TableLayout;
import Android.widget.TextView;

public class appwig extends Activity {  
    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.maindemo);  //<- includes the grid called "board"
      int vh = 0;   
      int vw = 0;

      //Test-1 used the xml layout (which is displayed on the screen):
      TableLayout tl = (TableLayout) findViewById(R.id.board);  
      tl = (TableLayout) findViewById(R.id.board);
      vh = tl.getHeight();     //<- getHeight returned 0, Why?  
      vw = tl.getWidth();     //<- getWidth returned 0, Why?   

      //Test-2 used a simple dynamically generated view:        
      TextView tv = new TextView(this);
      tv.setHeight(20);
      tv.setWidth(20);
      vh = tv.getHeight();    //<- getHeight returned 0, Why?       
      vw = tv.getWidth();    //<- getWidth returned 0, Why?

    } //eof method
} //eof class
207
greenset

OPはもうなくなったと思いますが、この答えが将来の検索者を助けることができるなら、私が見つけた解決策を投稿すると思いました。このコードをonCreate()メソッドに追加しました:

編集: 07/05/11コメントからのコードを含める:

final TextView tv = (TextView)findViewById(R.id.image_test);
ViewTreeObserver vto = tv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        LayerDrawable ld = (LayerDrawable)tv.getBackground();
        ld.setLayerInset(1, 0, tv.getHeight() / 2, 0, 0);
        ViewTreeObserver obs = tv.getViewTreeObserver();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            obs.removeOnGlobalLayoutListener(this);
        } else {
            obs.removeGlobalOnLayoutListener(this);
        }
    }

});

最初に、TextViewへの最後の参照を取得します(onGlobalLayout()メソッドでアクセスするため)。次に、ViewTreeObserverからTextViewを取得し、OnGlobalLayoutListenerを追加して、onGLobalLayoutをオーバーライドし(ここで呼び出すスーパークラスメソッドではないようです...)、このリスナーにビューの測定値を知る必要があるコードを追加します。すべてが期待どおりに機能するため、これが役立つことを願っています。

413
kcoppock

代替ソリューションを追加して、アクティビティのonWindowFocusChangedメソッドをオーバーライドすると、そこからgetHeight()、getWidth()の値を取得できるようになります。

@Override
public void onWindowFocusChanged (boolean hasFocus) {
        // the height will be set at this point
        int height = myEverySoTallView.getMeasuredHeight(); 
}
82
JustDanyul

まだ描画されていない要素の幅と高さを取得しようとしています。

デバッグを使用して、ある時点で停止すると、デバイスの画面がまだ空であることがわかります。これは、要素がまだ描画されていないためです。存在します。

そして、私は間違っているかもしれませんが、setWidth()は常に尊重されず、Layoutはその子をレイアウトし、それらを測定する方法を決定します(child.measure()を呼び出します)。したがって、setWidth()を設定した場合、要素が描画された後にこの幅を取得することは保証されません。

必要なのは、ビューが実際に描画された後のどこかでgetMeasuredWidth()(ビューの最新のメジャー)を使用することです。

最適なタイミングを見つけるために、Activityライフサイクルを調べてください。

http://developer.Android.com/reference/Android/app/Activity.html#ActivityLifecycle

次のようにOnGlobalLayoutListenerを使用することをお勧めします。

yourView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (!mMeasured) {
                // Here your view is already layed out and measured for the first time
                mMeasured = true; // Some optional flag to mark, that we already got the sizes
            }
        }
    });

このコードをonCreate()に直接配置することができ、ビューがレイアウトされるときに呼び出されます。

19
Alex Orlov

このようなビューの投稿メソッドを使用します

post(new Runnable() {   
    @Override
    public void run() {
        Log.d(TAG, "width " + MyView.this.getMeasuredWidth());
        }
    });
15
Boris Rusev

onGlobalLayout()を使用してTextViewのカスタム書式設定を試みましたが、@ George Baileyが気づいたように、onGlobalLayout()は実際に2回呼び出されます。最初のレイアウトパスで1回、テキストの変更後2回です。

View.onSizeChanged() は、テキストを変更した場合、メソッドが(レイアウトパス中に)1回だけ呼び出されるため、私にとってはうまく機能します。これにはTextViewのサブクラス化が必要でしたが、APIレベル11以降では View. addOnLayoutChangeListener() を使用してサブクラス化を回避できます。

もう1つ、View.onSizeChanged()でビューの正しい幅を取得するには、layout_widthmatch_parentではなく、wrap_contentに設定する必要があります。

7
Y2i

実際の画像を取得する前に、コンストラクタでサイズを取得しようとしていますか、または他のメソッドを実行しようとしていますか?

すべてのコンポーネントが実際に測定される前に寸法を取得することはありません(xmlは表示サイズ、親の位置などを知らないため)

OnSizeChanged()の後に値を取得してみてください(ゼロで呼び出すこともできます)、または実際の画像が取得されるのを待つだけです。

2
Alex Orlov

私はこれを見る必要があると思います:ビューのonSizeChanged()を使用します。 onSizeChanged()を使用してレイアウトまたはビューの高さと幅を動的に取得する方法に関する拡張コードスニペットがあります http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height -dimensions.html

2

F.Xとして。前述のように、OnLayoutChangeListenerを使用して、それ自体を追跡するビューに使用できます

view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        // Make changes
    }
});

初期レイアウトのみが必要な場合は、コールバックからリスナーを削除できます。

2
Zeophlite

ViewTreeObserveronWindowFocusChanged()はまったく必要ありません。

TextViewをレイアウトとして膨らませたり、その中にコンテンツを入れてLayoutParamsを設定したりすると、getMeasuredHeight()getMeasuredWidth()を使用できます。

BUTあなたはLinearLayoutsに注意してください(他のViewGroupsである可能性もあります)。問題は、onWindowFocusChanged()の後に幅と高さを取得できることですが、ビューを追加しようとすると、すべてが描画されるまでその情報を取得できません。複数のTextViewsLinearLayoutsに追加して、FlowLayout(ラッピングスタイル)を模倣しようとしたため、Listenersを使用できませんでした。プロセスが開始されると、同期して続行する必要があります。そのような場合、レイアウトにビューを追加するときに必要になるため、後で使用するために変数の幅を保持したい場合があります。

1
Genom

提案されたソリューションは機能しますが、ViewTreeObserver.OnGlobalLayoutListenerのドキュメントに基づいているため、すべての場合に最適なソリューションとは限りません

ビューツリー内のビューのグローバルレイアウト状態または可視性が変更されたときに呼び出されるコールバックのインターフェイス定義。

つまり、何度も呼び出され、常にビューが測定されるわけではありません(ビューの高さと幅が決定されます)

別の方法は、ViewTreeObserver.OnPreDrawListenerを使用することです。これは、ビューを描画する準備ができて、すべての測定値がある場合にのみ呼び出されます。

final TextView tv = (TextView)findViewById(R.id.image_test);
ViewTreeObserver vto = tv.getViewTreeObserver();
vto.addOnPreDrawListener(new OnPreDrawListener() {

    @Override
    public void onPreDraw() {
        tv.getViewTreeObserver().removeOnPreDrawListener(this);
        // Your view will have valid height and width at this point
        tv.getHeight();
        tv.getWidth();
    }

});
1
Kayvan N

高さと幅は、リクエストしているときまでにビューが作成されていないためゼロです。最も簡単な解決策は

view.post(new Runnable() {
    @Override
    public void run() {
        view.getHeight(); //height is ready
        view.getWidth(); //width is ready
    }
});

この方法は、短くて鮮明なので、他の方法と比べて優れています。

0
Shivam Yadav

Viewのライフサイクルを確認する必要があります。 http://developer.Android.com/reference/Android/view/View.html 通常、アクティビティがonResumeになるまで、幅と高さを確実に知る必要はありません。状態。

0
Andrey Novikov

OnResume()で呼び出されるブロードキャストを使用できます

例えば:

int vh = 0;   
int vw = 0;

public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.maindemo);  //<- includes the grid called "board"

      registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                TableLayout tl = (TableLayout) findViewById(R.id.board);  
                tl = (TableLayout) findViewById(R.id.board);
                vh = tl.getHeight();       
                vw = tl.getWidth();               
            }
      }, new IntentFilter("Test"));
}

protected void onResume() {
        super.onResume();

        Intent it = new Intent("Test");
        sendBroadcast(it);

}

Kcoppockが応答した理由で、OnCreate()、onStart()、またはonResume()でもビューの高さを取得できません。