ビューの getWidth() と getHeight() が 0 を返す 質問する

ビューの getWidth() と getHeight() が 0 を返す 質問する

Android プロジェクトのすべての要素を動的に作成しています。ボタンの幅と高さを取得して、ボタンを回転できるようにしようとしています。Android 言語の操作方法を学習しようとしているところです。ただし、0 が返されます。

調べてみたところ、メソッド内以外の場所で実行する必要があることがわかりましたonCreate()。実行方法の例を教えていただけると助かります。

現在のコードは次のとおりです:

package com.animation;

import android.app.Activity;
import android.os.Bundle;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.LinearLayout;

public class AnimateScreen extends Activity {


//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    LinearLayout ll = new LinearLayout(this);
    
    LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
    layoutParams.setMargins(30, 20, 30, 0);

    Button bt = new Button(this);
    bt.setText(String.valueOf(bt.getWidth()));
   
    RotateAnimation ra = new RotateAnimation(0,360,bt.getWidth() / 2,bt.getHeight() / 2);
    ra.setDuration(3000L);
    ra.setRepeatMode(Animation.RESTART);
    ra.setRepeatCount(Animation.INFINITE);
    ra.setInterpolator(new LinearInterpolator());

    bt.startAnimation(ra);
    
    ll.addView(bt,layoutParams);
    
    setContentView(ll);
}

ベストアンサー1

基本的な問題は、実際の測定値を得るために描画フェーズを待たなければならないことです (特にwrap_contentや のような動的な値の場合match_parent)。しかし、通常このフェーズは まで完了していませんonResume()。そのため、このフェーズを待つための回避策が必要です。これにはさまざまな解決策があります。

1. 描画/レイアウトイベントをリッスンする: ViewTreeObserver

ViewTreeObserverはさまざまな描画イベントで起動されます。通常はOnGlobalLayoutListener測定値を取得するために必要なのは、リスナー内のコードがレイアウト フェーズの後に呼び出され、測定値が準備されることです。

view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        view.getHeight(); //height is ready
    }
});

: リスナーはすぐに削除されます。そうしないと、レイアウト イベントごとに起動されます。SDKレベル 16 未満のアプリをサポートする必要がある場合は、これを使用してリスナーを登録解除します。

public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)

2. レイアウトキューに実行可能ファイルを追加します: View.post()

あまり知られていないが、私のお気に入りの解決策。基本的には、自分のランナブルでViewのpostメソッドを使用するだけです。これは基本的に、ビューのメジャー、レイアウトなどの後にコードをキューに入れます。ロマン・ギイ:

UIイベントキューはイベントを順番に処理します。setContentView()が呼び出されると、イベントキューにはレイアウトの再レイアウトを要求するメッセージが含まれるため、キューに投稿したものはすべてレイアウトパスの後に実行されます。

例:

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

に対する利点ViewTreeObserver:

  • コードは一度だけ実行されるため、実行後にオブザーバーを無効にする必要がなくなり、面倒な作業が省けます。
  • より簡潔な構文

参考文献:


3. ViewsのonLayoutメソッドを上書きする

これは、ロジックをビュー自体にカプセル化できる特定の状況でのみ実用的です。それ以外の場合は、非常に冗長で扱いにくい構文になります。

view = new View(this) {
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        view.getHeight(); //height is ready
    }
};

また、onLayoutは何度も呼び出されるので、メソッド内で何を行うかを考慮するか、最初の1回以降はコードを無効にしてください。

4. レイアウトフェーズを経たかどうかを確認する

UI の作成中に複数回実行されるコードがある場合は、次のサポート v4 lib メソッドを使用できます。

View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {
   viewYouNeedHeightFrom.getHeight();
}

ビューが最後にウィンドウにアタッチまたはデタッチされてから少なくとも 1 つのレイアウトを通過した場合は true を返します。

追加: 静的に定義された測定値の取得

静的に定義された高さ/幅を取得するだけで十分な場合は、次のようにします。

ただし、これは描画後の実際の幅/高さとは異なる可能性があることに注意してください。Javadoc では、この違いについてさらに詳しく説明しています。

ビューのサイズは幅と高さで表現されます。ビューには実際には幅と高さの値が 2 組あります。

最初のペアは、測定された幅と測定された高さと呼ばれます。これらの寸法は、ビューが親内でどのくらいの大きさになるかを定義します (詳細については、レイアウトを参照してください)。測定された寸法は、getMeasuredWidth() と getMeasuredHeight() を呼び出すことによって取得できます。

2 番目のペアは、単に幅と高さ、または描画幅と描画高さと呼ばれることもあります。これらの寸法は、描画時およびレイアウト後の画面上のビューの実際のサイズを定義します。これらの値は、測定された幅と高さと異なる場合がありますが、必ずしも異なる必要はありません。幅と高さは、getWidth() および getHeight() を呼び出すことで取得できます。

おすすめ記事