2010-03-26 5 views
17

Eine unserer Ansichten hat eine ScrollView als Root-Layout. Wenn das Gerät gedreht wird und aufgerufen wird, möchten wir in der Lage sein, die neue Breite/Höhe des ScrollView zu erhalten. Unser Code wie folgt aussieht:Wie bekomme ich eine neue Breite/Höhe des Root-Layouts in onConfigurationChanged?

@Override 
public void onConfigurationChanged(Configuration newConfig) { 
    Log.d(TAG, "Width: '" + findViewById(R.id.scrollview).getWidth() + "'"); 
    Log.d(TAG, "Height: '" + findViewById(R.id.scrollview).getHeight() + "'"); 

    super.onConfigurationChanged(newConfig); 

    Log.d(TAG, "Width: '" + findViewById(R.id.scrollview).getWidth() + "'"); 
    Log.d(TAG, "Height: '" + findViewById(R.id.scrollview).getHeight() + "'"); 
} 

Der entsprechende Abschnitt unserer AndroidManifest.xml wie folgt aussieht:

<activity android:name=".SomeActivity" 
    android:configChanges="keyboardHidden|orientation"> 
    <intent-filter> 
     <action android:name="android.intent.action.MAIN" /> 
    </intent-filter> 
</activity> 

Und schließlich der relevante Teil unseres Layout sieht wie folgt aus:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/scrollview" 
    android:layout_height="fill_parent" 
    android:layout_width="fill_parent" 
    > 
    <LinearLayout android:id="@+id/container" 
     android:orientation="vertical" 
     android:layout_height="fill_parent" 
     android:minHeight="200dip" 
     android:layout_width="fill_parent" 
     > 

Auf unserem Droid erwarteten wir, dass die ScrollView-Breite bei der Umschaltung in Querformat auf 854 und beim Zurückschalten auf Hochformat auf 480 (und die Höhe auf den entsprechenden Schalter minus der Menüleiste) . Wir sehen jedoch das Gegenteil. Hier ist unsere LogCat:

// Switching to landscape: 
03-26 11:26:16.490: DEBUG/ourtag(17245): Width: '480' // Before super 
03-26 11:26:16.490: DEBUG/ourtag(17245): Height: '778' // Before super 
03-26 11:26:16.529: DEBUG/ourtag(17245): Width: '480' // After super 
03-26 11:26:16.536: DEBUG/ourtag(17245): Height: '778' // After super 

// Switching to portrait: 
03-26 11:26:28.724: DEBUG/ourtag(17245): Width: '854' // Before super 
03-26 11:26:28.740: DEBUG/ourtag(17245): Height: '404' // Before super 
03-26 11:26:28.740: DEBUG/ourtag(17245): Width: '854' // After super 
03-26 11:26:28.740: DEBUG/ourtag(17245): Height: '404' // After super 

ist klar, wir sind die Porträt Dimensionen bekommen, wenn wir auf Landschaft zu wechseln, und die Landschaft Dimensionen, wenn wir auf Hochformat wechseln. Gibt es etwas, was wir falsch machen? Wir könnten Hacky bekommen und das lösen, aber ich habe das Gefühl, dass es eine einfache Lösung gibt, die wir vermissen.

Antwort

7

getWidth() gibt die Breite zurück, während die Ansicht angelegt ist, was bedeutet, dass Sie warten müssen, bis sie auf den Bildschirm gezeichnet wird. onConfigurationChanged wird aufgerufen, bevor die Ansicht für die neue Konfiguration neu gezeichnet wird. Daher glaube ich nicht, dass Sie die neue Breite erst später abrufen können.

+0

Das ist, was wir Angst haben. Die erste Lösung, die wir uns vorstellen können, besteht darin, einen Thread zu erzeugen, 100ms oder etwas zu warten und dann die Breite/Höhe zu nehmen. Gibt es etwas weniger Hacky, das wir tun können? – jakeboxer

+12

Einen Faden spawnen? Oh nein tu das nicht! Sie können ein Runnable in einem Handler (oder zum Beispiel auf dem UI-Thread mit View.post()) einfach posten. Sie können auch einen Listener mit dem ViewTreeObserver registrieren, auf ein Ereignis zum Ändern der Größenänderung in einer benutzerdefinierten Ansicht warten usw. –

+0

Listening Der ViewTreeObserver klingt für mich nach der besten Lösung, da ich die Wartemethode ein wenig hacky finde. – jqpubliq

34

Für diejenigen, die eine detailliertere Beschreibung der Lösung suchen: Sie können die ViewTreeObserver Ihrer Ansicht verwenden und eine OnGlobalLayoutListener registrieren.

@Override 
public void onConfigurationChanged(Configuration newConfiguration) { 
    super.onConfigurationChanged(newConfiguration); 
    final View view = findViewById(R.id.scrollview); 

    ViewTreeObserver observer = view.getViewTreeObserver(); 
    observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 

     @Override 
     public void onGlobalLayout() { 
      Log.v(TAG, 
        String.format("new width=%d; new height=%d", view.getWidth(), 
          view.getHeight())); 
      view.getViewTreeObserver().removeOnGlobalLayoutListener(this); 
     } 
    }); 
} 
+6

Um eine Endlosschleife von Aufrufen von 'onGlobalLayout' zu vermeiden, musste ich den Listener entfernen, nachdem ich meine Berechnungen basierend auf den neuen Größen der Ansichten durchgeführt hatte:' view.getViewTreeObserver(). RemoveGlobalOnLayoutListener (this); ' –

+0

Ja, Sie haben Recht . Ich habe das Code-Snippet aktualisiert. Vielen Dank. –

+1

danke, ich hatte über ViewTreeObserver vergessen ... auch für andere Klarstellung: removeGlobalOnLayoutListener ist veraltet.Verwenden Sie stattdessen "removeOnGlobalLayoutListener". – j2emanue

10

Wenn onGlobalLayout nennt es nicht sicher ist, dass die Ansicht entsprechend die neuen Layout Ausrichtung der Größe verändert wurde, für mich, so dass nur die folgende Lösung richtig gearbeitet:

@Override 
public void onConfigurationChanged(Configuration newConfig) { 
final int oldHeight = mView.getHeight(); 
final int oldWidth = mView.getWidth(); 

mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
     @Override 
     public void onGlobalLayout() { 
      if (mView.getHeight() != oldHeight && mView.getWidth() != oldWidth) { 
       mView.getViewTreeObserver().removeOnGlobalLayoutListener(this); 
       //mView now has the correct dimensions, continue with your stuff 
      } 
     } 
    }); 
    super.onConfigurationChanged(newConfig);} 
+0

Danke, ich musste auch überprüfen, dass die Größe vor dem Entfernen des Zuhörers geändert. Nun wird onGlobalLayout zweimal aufgerufen und ich bekomme erst beim zweiten Mal die richtige Größe. Ich weiß nicht warum, aber:/ –

+0

Sollte die akzeptierte Antwort sein. Obwohl die Überprüfung sowohl der Höhe als auch der Breite nicht notwendig ist, reicht eine. – 0101100101

+0

unbedingt erforderlich, wenn der Benutzer mit den Animationsgeschwindigkeiten in den Telefoneinstellungen optimiert wurde – rupps

Verwandte Themen