Uno de nuestros puntos de vista tiene un ScrollView como su raíz diseño. Cuando se gira el dispositivo y onConfigurationChanged() se llama, nos gustaría ser capaces de obtener la ScrollView‘s nueva anchura y altura. Nuestro código se parece a esto:

@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 sección correspondiente de nuestra AndroidManifest.xml se parece a esto:

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

Y, por último, la parte pertinente de nuestro diseño se parece a esto:

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

En nuestro Droid, que nos espera a ver el ScrollView del ancho de ir a 854 cuando se enciende en el paisaje, y a 480 cuando se vuelve a encender la orientación y la altura de hacer el equivalente a cambiar, menos la barra de menú). Sin embargo, estamos viendo lo contrario. Aquí está nuestra 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

Claramente, estamos obteniendo el retrato dimensiones cuando cambiamos el paisaje, y el paisaje dimensiones cuando se cambia a vertical. Hay algo que estamos haciendo mal? Podríamos conseguir hacky y resolver esto, pero siento que hay una solución simple que nos falta.

InformationsquelleAutor jakeboxer | 2010-03-26

3 Comentarios

  1. 7

    getWidth() devuelve la anchura como la Vista se presenta, lo que significa que debe esperar hasta que se dibuja en la pantalla. onConfigurationChanged se llama antes de volver a dibujar la vista para que la nueva configuración y, entonces, yo no creo que usted será capaz de obtener su nuevo ancho hasta más tarde.

    • Que es lo que más temían. La primera solución que podemos pensar es generar un hilo, espere 100ms o algo, y luego agarra la anchura/altura. Hay cualquier cosa menos chapucero que podemos hacer de que?
    • El desove de un hilo? Oh no, no hagas esto! Usted puede simplemente publicar un Ejecutable en un Controlador (o en el subproceso de interfaz de usuario utilizando la Vista.post() por ejemplo). También se puede registrar un oyente con el ViewTreeObserver, espere un cambio de tamaño evento de cambio en una Vista personalizada, etc.
    • Escuchar la ViewTreeObserver suena como la mejor solución para mí como yo encontrar la espera de método un poco chapucero.
    • Ah, excelente. Nunca habíamos oído hablar de la ViewTreeObserver antes. Romain Guy, si puesto que como respuesta, voy a votar y aceptar. De lo contrario, sólo voy a aceptar esto.
    • Yo realmente no obtener lo que el punto de tener un objeto de Configuración llamado newConfig pasados en el método si no se puede utilizar para obtener la nueva altura y la anchura. La Configuración de la clase, incluso ha screenWidthDp y screenHeightDp los miembros de la clase.
    • runonuithread se llama inmediatamente antes de la publicación se realiza, al menos, el mismo parece ser cierto para los post, así que sí sería necesario generar un nuevo hilo si usted utiliza la espera de método. el uso de la viewtreeobserver ya que es menos chapucero.

  2. 36

    Para aquellos que buscan una más detallada descripción de la solución: Usted puede utilizar el ViewTreeObserver de su vista y registrar un 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);
            }
        });
    }
    • Para evitar un bucle infinito de llamadas a onGlobalLayout, tuve que quitar el detector después de hacer mis cálculos basados en los nuevos tamaños de las vistas: view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
    • Sí tienes razón. He actualizado el fragmento de código. Gracias.
    • gracias, me había olvidado de viewTreeObservers …también para los demás aclaración: removeGlobalOnLayoutListener está en desuso. el uso de «removeOnGlobalLayoutListener» en su lugar.
    • Esto le da a resultados inconsistentes. A veces se acierta, a veces no. OMI escuchar a un evento de cambio de tamaño en una costumbre View es más probable que el camino a seguir.
    • buena manera de hacer el trato, es también suave durante roration
    • de acuerdo con @ChristopherPerry, probado esto, pero a veces simplemente no tiene ningún efecto y da los mismos valores. Mejor uso de la vista personalizada y reemplazar onSizeChanged evento y que funcionan siempre.

  3. 14

    Cuando onGlobalLayout llamado no es seguro que la vista se ha cambiado el tamaño de acuerdo a la nueva orientación de diseño, así que para mí, sólo por debajo de la solución funcionó correctamente:

    @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);}
    • Gracias, yo también tenía que comprobar que el tamaño ha cambiado antes de quitar el oyente. Ahora onGlobalLayout es llamado dos veces y me sale el tamaño adecuado sólo en el segundo tiempo. No sé por qué, a pesar de que :/
    • Debe ser aceptado respuesta. A pesar de que la comprobación de la altura y la anchura no es necesario, es suficiente.
    • sin duda necesario en el caso de que el usuario ha ajustado con la animación de velocidades en la configuración del teléfono

Dejar respuesta

Please enter your comment!
Please enter your name here