wake-up-neo.com

Wie erhalte ich die Dimensionen einer Ansicht?

Ich habe eine Ansicht aus TableLayout, TableRow and TextView. Ich möchte, dass es wie ein Gitter aussieht. Ich muss die Höhe und Breite dieses Gitters ermitteln. Die Methoden getHeight() und getWidth() geben immer 0 zurück. Dies geschieht, wenn ich das Raster dynamisch formatiere und auch eine XML-Version verwende. 

Wie erhalte ich die Dimensionen für eine Ansicht? 


Hier ist mein Testprogramm, das ich in Debug zur Überprüfung der Ergebnisse verwendet habe: 

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
204
greenset

Ich glaube, das OP ist längst vorbei, aber falls diese Antwort zukünftigen Suchern helfen kann, dachte ich, ich würde eine Lösung posten, die ich gefunden habe. Ich habe diesen Code meiner onCreate()-Methode hinzugefügt:

BEARBEITET: 07/05/11 um den Code aus den Kommentaren aufzunehmen:

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);
        }
    }

});

Zuerst bekomme ich eine abschließende Referenz auf meine TextView (Zugriff in der onGlobalLayout()-Methode). Als Nächstes erhalte ich die ViewTreeObserver von meiner TextView und füge eine OnGlobalLayoutListener hinzu, überschreibe onGLobalLayout (es scheint keine Superklassenmethode zu geben, die hier aufgerufen werden soll ...) und fügt meinen Code hinzu. Alles funktioniert wie erwartet für mich, also hoffe ich, dass dies helfen kann.

410
kcoppock

Ich füge einfach eine alternative Lösung hinzu, überschreibt die onWindowFocusChanged-Methode Ihrer Aktivität und Sie können die Werte von getHeight (), getWidth () von dort abrufen. 

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

Sie versuchen, Breite und Höhe von Elementen abzurufen, die noch nicht gezeichnet wurden.

Wenn Sie Debug verwenden und an einem bestimmten Punkt anhalten, werden Sie feststellen, dass der Bildschirm Ihres Geräts noch leer ist. Dies liegt daran, dass Ihre Elemente noch nicht gezeichnet wurden. Sie können also weder die Breite noch die Höhe von etwas ermitteln, das ist noch nicht der Fall existieren.

Ich bin vielleicht falsch, aber setWidth() wird nicht immer respektiert. Layout legt die untergeordneten Elemente fest und entscheidet, wie sie gemessen werden sollen (Aufruf von child.measure()). Wenn Sie setWidth() einstellen, werden Sie nicht garantiert, dass diese Breite angezeigt wird.

Sie müssen getMeasuredWidth() (das letzte Maß Ihrer Ansicht) irgendwo verwenden, nachdem die Ansicht tatsächlich gezeichnet wurde.

Sehen Sie sich den Activity Lebenszyklus an, um den besten Moment zu finden.

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

Ich glaube, es ist eine gute Praxis, OnGlobalLayoutListener wie folgt zu verwenden:

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
            }
        }
    });

Sie können diesen Code direkt in onCreate() platzieren. Er wird aufgerufen, wenn Ansichten angeordnet werden.

19
Alex Orlov

Verwenden Sie die Post-Methode der View auf diese Weise

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

Ich habe versucht, onGlobalLayout() für die benutzerdefinierte Formatierung einer TextView zu verwenden, aber wie @George Bailey bemerkt hat, wird onGlobalLayout() in der Tat zweimal aufgerufen: einmal im anfänglichen Layoutpfad und beim zweiten Ändern des Textes.

View.onSizeChanged() funktioniert für mich besser, da die Methode nur einmal (während des Layout-Durchlaufs) aufgerufen wird, wenn ich den Text dort modifiziere. Dies erforderte die Unterklassifizierung von TextView, aber auf API Level 11+ View. addOnLayoutChangeListener() kann eine Unterklassifizierung vermieden werden.

Um die korrekte Breite der Ansicht in View.onSizeChanged() zu erhalten, sollte layout_width auf match_parent und nicht auf wrap_content gesetzt werden.

7
Y2i

Versuchen Sie, Größen in einem Konstruktor oder einer anderen Methode zu ermitteln, die ausgeführt wird, BEVOR Sie das eigentliche Bild erhalten?

Sie erhalten keine Bemaßungen, bevor alle Komponenten tatsächlich gemessen werden (da Ihre XML-Datei Ihre Anzeigegröße, die Positionen der Eltern und was auch immer nicht kennt).

Versuchen Sie, Werte nach onSizeChanged () zu erhalten (obwohl mit Null aufgerufen werden kann), oder warten Sie einfach, wenn Sie ein aktuelles Bild erhalten.

2
Alex Orlov

Ich denke, das ist, was Sie sich ansehen müssen: Verwenden Sie onSizeChanged() Ihrer Ansicht. Hier ein EXTENDED-Code-Snippet, wie Sie mit onSizeChanged() die Höhe und Breite Ihres Layouts oder der Ansicht dynamisch ermitteln http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions .html

2

Als F.X. Wie bereits erwähnt, können Sie eine OnLayoutChangeListener für die Ansicht verwenden, die Sie selbst verfolgen möchten

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
    }
});

Sie können den Listener im Rückruf entfernen, wenn Sie nur das ursprüngliche Layout möchten.

2
Zeophlite

ViewTreeObserver und onWindowFocusChanged() sind überhaupt nicht notwendig.

Wenn Sie die TextView als Layout aufblasen und/oder Inhalte hinzufügen und LayoutParams setzen, können Sie getMeasuredHeight() und getMeasuredWidth() verwenden.

ABERSie müssen vorsichtig mit LinearLayoutssein (vielleicht auch andere ViewGroups). Das Problem dabei ist, dass Sie die Breite und Höhe nach onWindowFocusChanged() abrufen können. Wenn Sie jedoch versuchen, einige Ansichten hinzuzufügen, können Sie diese Informationen erst abrufen, wenn alles gezeichnet wurde. Ich habe versucht, mehrere TextViews zu LinearLayouts hinzuzufügen, um eine FlowLayout (Umbruchart) nachzuahmen, und konnte daher Listeners nicht verwenden. Sobald der Prozess gestartet ist, sollte er synchron weiterlaufen. In einem solchen Fall möchten Sie möglicherweise die Breite in einer Variablen beibehalten, um sie später zu verwenden, da Sie sie beim Hinzufügen von Ansichten zum Layout möglicherweise benötigen.

1
Genom

Obwohl die vorgeschlagene Lösung funktioniert, ist sie möglicherweise nicht für jeden Fall die beste Lösung, da sie auf der Dokumentation für ViewTreeObserver.OnGlobalLayoutListener basiert.

Schnittstellendefinition für einen Rückruf, der aufgerufen wird, wenn sich der globale Layoutstatus oder die Sichtbarkeit von Ansichten in der Ansichtsstruktur ändert. 

was bedeutet, dass es viele Male aufgerufen wird und nicht immer die Ansicht gemessen wird (ihre Höhe und Breite wurde bestimmt)

Eine Alternative ist, ViewTreeObserver.OnPreDrawListener zu verwenden, der nur dann aufgerufen wird, wenn die Ansicht gezeichnet werden kann und alle ihre Messungen vorhanden sind.

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

Höhe und Breite sind Null, da die Ansicht zum Zeitpunkt der Anforderung von Höhe und Breite noch nicht erstellt wurde. Eine einfachste Lösung ist

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

Diese Methode ist im Vergleich zu anderen Methoden gut, da sie kurz und knackig ist.

0
Shivam Yadav

Sie sollten sich lieber den Lebenszyklus von View ansehen: http://developer.Android.com/reference/Android/view/View.html Im Allgemeinen sollten Sie Breite und Höhe nicht sicher kennen, bis Ihre Aktivität den Status onResume erreicht.

0
Andrey Novikov

Sie können eine Sendung verwenden, die in OnResume () aufgerufen wird.

Zum Beispiel:

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);

}

Sie können die Höhe einer Ansicht in OnCreate (), onStart () oder sogar in onResume () nicht ermitteln, weil kcoppock darauf reagiert hat