2010-03-26 7 views
17

Una delle nostre viste ha un ScrollView come layout di root. Quando il dispositivo viene ruotato e viene chiamato , vorremmo essere in grado di ottenere la nuova larghezza/altezza dello ScrollView. Il nostro codice è simile al seguente:Come ottenere NUOVA larghezza/altezza del layout di root 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() + "'"); 
} 

La sezione dedicata del nostro AndroidManifest.xml assomiglia a questo:

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

E, infine, la quota di competenza del nostro layout si presenta così:

<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" 
     > 

Sul nostro Droid, ci aspettavamo di vedere la larghezza della ScrollView andare a 854 quando passa nel paesaggio, e di 480 quando si ritorna al ritratto (e l'altezza fare lo switch equivalente, meno la barra dei menu) . Tuttavia, stiamo vedendo il contrario. Ecco la nostra 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 

Chiaramente, stiamo ottenendo le dimensioni ritratto quando si passa al paesaggio, e le dimensioni del paesaggio quando si passa al ritratto. C'è qualcosa che stiamo sbagliando? Potremmo ottenere hacky e risolvere questo problema, ma mi sembra che ci sia una soluzione semplice che ci manca.

risposta

7

getWidth() restituisce la larghezza, la vista è disposto, il che significa che c'è bisogno di aspettare fino a quando non viene disegnato sullo schermo. onConfigurationChanged viene chiamato prima di ridisegnare la vista per la nuova configurazione e quindi non penso che sarete in grado di ottenere la vostra nuova larghezza fino a tardi.

+0

Questo è quello che temevamo. La prima soluzione che possiamo pensare è generare un thread, attendere 100ms o qualcosa, e quindi prendere la larghezza/altezza. C'è qualcosa di meno hacky che possiamo fare? – jakeboxer

+12

Generare una discussione? Oh no non farlo! Puoi semplicemente pubblicare un Runnable in un Handler (o sul thread dell'interfaccia utente usando per esempio View.post().) Puoi anche registrare un listener con ViewTreeObserver, attendere un evento di modifica del ridimensionamento in una vista personalizzata, ecc. –

+0

Ascolto al ViewTreeObserver mi sembra la soluzione migliore perché trovo il metodo di attesa un po 'hacky. – jqpubliq

34

Per coloro che cercano una descrizione della soluzione più dettagliata: È possibile utilizzare il ViewTreeObserver della visualizzazione e registrare uno OnGlobalLayoutListener.

@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

Per evitare un ciclo infinito di chiamate a 'onGlobalLayout', ho dovuto rimuovere il listener dopo aver eseguito i calcoli in base alle nuove dimensioni delle viste:' view.getViewTreeObserver(). RemoveGlobalOnLayoutListener (this); ' –

+0

Sì hai ragione . Ho aggiornato lo snippet di codice. Grazie. –

+1

grazie per avermi dimenticato di viewTreeObservers ... anche per altri chiarimenti: removeGlobalOnLayoutListener è deprecato.utilizzare invece "removeOnGlobalLayoutListener". – j2emanue

10

Quando onGlobalLayout chiamato non è sicuro che la vista è stata ridimensionata di conseguenza per il nuovo orientamento di layout, quindi per me solo la soluzione qui di seguito ha funzionato correttamente:

@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

Grazie, ho anche dovuto controllare che la dimensione cambiata prima di rimuovere il listener. Ora onGlobalLayout viene chiamato due volte e ottengo la giusta dimensione solo la seconda volta. Non so perché comunque:/ –

+0

Dovrebbe essere la risposta accettata. Anche se il controllo di altezza e larghezza non è necessario, uno è sufficiente. – 0101100101

+0

sicuramente necessario nel caso in cui l'utente abbia ottimizzato le velocità di animazione nelle impostazioni del telefono – rupps

Problemi correlati