Android: deshabilita temporalmente los cambios de orientación en una actividad


116

Mi actividad principal tiene un código que realiza algunos cambios en la base de datos que no deben interrumpirse. Estoy haciendo el trabajo pesado en otro hilo y usando un diálogo de progreso que establecí como no cancelable. Sin embargo, noté que si giro mi teléfono, se reinicia la actividad, lo cual es REALMENTE malo para el proceso que se estaba ejecutando, y obtengo un cierre forzado.

Lo que quiero hacer es deshabilitar programáticamente los cambios de orientación de la pantalla hasta que se complete mi proceso, momento en el que se habilitan los cambios de orientación.


Dado que nadie parece mencionar esta parte, querrá importar android.content.pm.ActivityInfo para usar el identificador ActivityInfo.
zsalwasser


1
Consulte: stackoverflow.com/a/32885911/2673792 para obtener la mejor solución
Sudhir Sinha

Respuestas:


165

Como explica Chris en su auto-respuesta , llamando

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

y entonces

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

realmente funciona como un encanto ... ¡en dispositivos reales!

No crea que está roto al probar en el emulador, el atajo ctrl + F11 SIEMPRE cambia la orientación de la pantalla, sin emular movimientos de sensores.

EDITAR: esta no fue la mejor respuesta posible. Como se explica en los comentarios, existen problemas con este método. La verdadera respuesta está aquí .


No pude localizar esas constantes. Gracias por eso.
Christopher Perry

41
Hay un problema con estos métodos ... Parece que si llamas a setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); cuando el dispositivo no está en su uso de orientación predeterminada, la orientación de la actividad se cambia inmediatamente (se destruye y se vuelve a crear) a la orientación predeterminada del dispositivo. Por ejemplo, en un teléfono, si lo sostiene en orientación horizontal, la actividad cambia a vertical y vuelve a horizontal al reactivar los sensores. El mismo problema opuesto con un Archos A5 IT: usarlo en retrato hace que la actividad cambie a paisaje y vuelva a retrato.
Kevin Gaudin

1
La respuesta real a la pregunta original está ahí: stackoverflow.com/questions/3821423/…
Kevin Gaudin

2
Esto no funcionó para mí. Sin embargo, este funcionó: stackoverflow.com/a/10488012/1369016 Tuve que llamar a setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); o setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); basado en la orientación actual recuperada de getResources (). getConfiguration (). Orientación.
Tiago

ActivityInfo.SCREEN_ORIENTATION_SENSORno respeta el bloqueo de orientación nativo de Android. Restableciendo la orientación a ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIEDhace.
tvkanters

43

Ninguna de las otras respuestas funcionó perfectamente para mí, pero esto es lo que encontré que hace.

Bloquear la orientación a la actual ...

if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

Cuando se deba volver a permitir el cambio de orientación, vuelva a establecer el valor predeterminado ...

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

9
El problema con esto es que Configuration.ORIENTATION_PORTRAITse devolverá en ambos modos de paisaje (es decir, "normal" y al revés). Entonces, si el teléfono está en orientación horizontal invertida y lo configura, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPEse volteará boca abajo. En API 9, ActivityInfo introduce SCREEN_ORIENTATION_REVERSE_LANDSCAPEconstante, pero no veo una forma de detectar dicha orientación a través de la Configurationclase.
Błażej Czapp

1
Esto funcionó. La respuesta a la preocupación anterior se encuentra en esta respuesta. stackoverflow.com/a/10453034/1223436
Zack

También funcionó como un encanto para mis necesidades, gracias brillantes
user2029541

39

Aquí hay una solución más completa y actualizada que funciona para API 8+, funciona para retrato y paisaje inverso, y funciona en una pestaña Galaxy donde la orientación "natural" es horizontal (llame activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)para desbloquear la orientación):

@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
public static void lockActivityOrientation(Activity activity) {
    Display display = activity.getWindowManager().getDefaultDisplay();
    int rotation = display.getRotation();
    int height;
    int width;
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2) {
        height = display.getHeight();
        width = display.getWidth();
    } else {
        Point size = new Point();
        display.getSize(size);
        height = size.y;
        width = size.x;
    }
    switch (rotation) {
    case Surface.ROTATION_90:
        if (width > height)
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        else
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
        break;
    case Surface.ROTATION_180:
        if (height > width)
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
        else
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
        break;          
    case Surface.ROTATION_270:
        if (width > height)
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
        else
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        break;
    default :
        if (height > width)
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        else
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    }
}

Me funcionó muy bien con tabletas y teléfonos.
ScruffyFox

La única respuesta correcta que funciona en todo tipo de dispositivo para mí.
amdev

¡Definitivamente la mejor respuesta! Puede hacer este método staticy agregarlo Activity activitycomo parámetro.
caw

18

Para administrar también los modos de orientación inversa, he usado ese código para corregir la orientación de la actividad:

int rotation = getWindowManager().getDefaultDisplay().getRotation();

    switch(rotation) {
    case Surface.ROTATION_180:
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
        break;
    case Surface.ROTATION_270:
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);         
        break;
    case  Surface.ROTATION_0:
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        break;
    case Surface.ROTATION_90:
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        break;
    }

Y para permitir nuevamente la orientación:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

17

Úselo setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);para bloquear la orientación actual, ya sea horizontal o vertical.

Úselo setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);para desbloquear la orientación.


La mejor solución para un bloqueo temporal corto. No jugar con la orientación actual del sensor.
El increíble

2
funciona en Build.VERSION.SDK_INT> = 18, tdjprog da una respuesta más completa en esta página stackoverflow.com/a/41812971/5235263
bastami82


11

Gracias a todos. Modifiqué la solución de Pilot_51 para asegurarme de restaurar al estado anterior. También agregué un cambio para admitir pantallas que no son horizontales ni verticales (pero no lo he probado en una pantalla de este tipo).

prevOrientation = getRequestedOrientation();
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}

Luego para restaurarlo

setRequestedOrientation(prevOrientation);

Cosas buenas, no estoy seguro de por qué no usaste un switchaunque.

Olvidé limpiar y cambiar a un interruptor después de agregar la tercera opción.
ProjectJourneyman

Encontré que esto funciona sin tener que obtener la configuración actual si no tiene acceso al objeto de actividad, sino solo al contexto ActivityInfo.SCREEN_ORIENTATION_NOSENSOR | ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
max4ever

8
protected void setLockScreenOrientation(boolean lock) {
    if (Build.VERSION.SDK_INT >= 18) {
        setRequestedOrientation(lock?ActivityInfo.SCREEN_ORIENTATION_LOCKED:ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
        return;
    }

    if (lock) {
        switch (getWindowManager().getDefaultDisplay().getRotation()) {
            case 0: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); break; // value 1
            case 2: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); break; // value 9
            case 1: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); break; // value 0
            case 3: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); break; // value 8
        }
    } else
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); // value 10
}

¿Podría agregar alguna explicación a su respuesta?
slfan

cuando tenga algunos trabajos en segundo plano, simplemente llame a setLockScreenOrientation (verdadero) para bloquear la orientación y evitar destruir la actividad actual para recrearla. cuando se asegure de que estos trabajos hayan finalizado, llame a setLockScreenOrientation (false).
tdjprog

2
Esta es la mejor respuesta !
Fakher

7

Aquí hay una solución que funciona todo el tiempo y conserva la orientación actual (usando Activity.Info.SCREEN_ORIENTATION_PORTRAITconjuntos a 0 ° por ejemplo, pero el usuario puede tener una orientación de 180 ° como la actual).

// Scope: Activity

private void _lockOrientation() {
    if (super.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
        super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT);
    } else {
        super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
    }
}

private void _unlockOrientation() {
    super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}

2
Vale la pena mencionar: API 18+ solamente
Dmitry Zaytsev

1

Úselo ActivityInfo.SCREEN_ORIENTATION_USERsi desea rotar la pantalla solo si está habilitado en el dispositivo.


1

Esto funciona perfecto para mí. Resuelve el problema con la diferente "orientación natural" de la tableta / teléfono;)

int rotation = getWindowManager().getDefaultDisplay().getRotation();

        Configuration config = getResources().getConfiguration();
        int naturalOrientation;

        if (((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) &&
                config.orientation == Configuration.ORIENTATION_LANDSCAPE)
                || ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) &&
                config.orientation == Configuration.ORIENTATION_PORTRAIT)) {
            naturalOrientation = Configuration.ORIENTATION_LANDSCAPE;
        } else {
            naturalOrientation = Configuration.ORIENTATION_PORTRAIT;
        }

        // because getRotation() gives "rotation from natural orientation" of device (different on phone and tablet)
        // we need to update rotation variable if natural orienation isn't 0 (mainly tablets)
        if (naturalOrientation == Configuration.ORIENTATION_LANDSCAPE)
            rotation = ++rotation % 4;

        switch (rotation) {
            case Surface.ROTATION_0: //0
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                break;
            case Surface.ROTATION_90: //1
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                break;
            case Surface.ROTATION_180: //2
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
                break;
            case Surface.ROTATION_270: //3
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
                break;
        }
    } else {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }

0

Se me ocurrió una solución que depende de la rotación de la pantalla y luego decide la orientación del dispositivo. Al conocer la orientación, podemos bloquear la orientación y liberarla más tarde cuando sea necesario. Esta solución también puede determinar si el dispositivo está en modo horizontal inverso .

private void lockOrientation(){
    switch (((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation()) {


        // Portrait
        case Surface.ROTATION_0:
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            break;


        //Landscape     
        case Surface.ROTATION_90: 
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            break;


        // Reversed landscape
        case Surface.ROTATION_270:
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);             
            break;
    }
}

Luego, más tarde, si necesitamos liberar la orientación, podemos llamar a este método:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

0

Creo que este código es más fácil de leer.

private void keepOrientation() {

    int orientation = getResources().getConfiguration().orientation;
    int rotation = getWindowManager().getDefaultDisplay().getRotation();

    switch (rotation) {
        case Surface.ROTATION_0:
            if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            }
            break;
        case Surface.ROTATION_90:
            if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            }
            break;
        case Surface.ROTATION_180:
            if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
            }
            break;
        default:
            if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
            }
    }
}

0

He descubierto que se necesita una combinación de valores de rotación / orientación existentes para cubrir las cuatro posibilidades; están los valores de retrato / paisaje y la orientación natural del dispositivo. Digamos que la orientación natural de los dispositivos tendrá un valor de rotación de 0 grados cuando la pantalla esté en su orientación vertical u horizontal "natural". De manera similar, habrá un valor de rotación de 90 grados cuando esté en horizontal o vertical (observe que es opuesto a la orientación a 0 grados). Por lo tanto, los valores de rotación que no sean 0 o 90 grados implicarán una orientación "inversa". Ok, aquí hay un código:

public enum eScreenOrientation 
{
PORTRAIT (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT),
LANDSCAPE (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE),
PORTRAIT_REVERSE (ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT),
LANDSCAPE_REVERSE (ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE),
UNSPECIFIED_ORIENTATION (ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

    public final int activityInfoValue;

    eScreenOrientation ( int orientation )
    {
        activityInfoValue = orientation;
    }
}



public eScreenOrientation currentScreenOrientation ( )
{
    final int rotation = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();

    final int orientation = getResources().getConfiguration().orientation;
    switch ( orientation ) 
    {
    case Configuration.ORIENTATION_PORTRAIT:
        if ( rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90 )
            return eScreenOrientation.PORTRAIT;
        else
            return eScreenOrientation.PORTRAIT_REVERSE;
    case Configuration.ORIENTATION_LANDSCAPE:
        if ( rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90 )
            return eScreenOrientation.LANDSCAPE;
        else
            return eScreenOrientation.LANDSCAPE_REVERSE;
    default:
        return eScreenOrientation.UNSPECIFIED_ORIENTATION;
    }
}

public void lockScreenOrientation ( )
    throws UnsupportedDisplayException
{
    eScreenOrientation currentOrientation = currentScreenOrientation( );
    if ( currentOrientation == eScreenOrientation.UNSPECIFIED_ORIENTATION )
        throw new UnsupportedDisplayException("Unable to lock screen - unspecified orientation");
    else
        setRequestedOrientation( currentOrientation.activityInfoValue );
}

public void unlockScreenOrientation (  )
{
    setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED );
}

0

No me gustó la mayoría de las respuestas aquí, ya que en el desbloqueo lo configuraron como SIN ESPECIFICAR en comparación con el estado anterior. ProjectJourneyman lo tuvo en cuenta, lo cual fue genial, pero preferí el código de bloqueo de Roy. Entonces, mi recomendación sería una combinación de las dos:

private int prevOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;

private void unlockOrientation() {
    setRequestedOrientation(prevOrientation);
}

@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
private void lockOrientation() {
    prevOrientation = getRequestedOrientation();
    Display display = getWindowManager().getDefaultDisplay();
    int rotation = display.getRotation();
    int height;
    int width;
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2) {
        height = display.getHeight();
        width = display.getWidth();
    } else {
        Point size = new Point();
        display.getSize(size);
        height = size.y;
        width = size.x;
    }
    switch (rotation) {
        case Surface.ROTATION_90:
            if (width > height)
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            else
                setRequestedOrientation(9/* reversePortait */);
            break;
        case Surface.ROTATION_180:
            if (height > width)
                setRequestedOrientation(9/* reversePortait */);
            else
                setRequestedOrientation(8/* reverseLandscape */);
            break;
        case Surface.ROTATION_270:
            if (width > height)
                setRequestedOrientation(8/* reverseLandscape */);
            else
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            break;
        default :
            if (height > width)
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            else
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    }
}

0

Puedes usar

public void swapOrientaionLockState(){
    try{
        if (Settings.System.getInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 1) {
            Display defaultDisplay = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
            Settings.System.putInt(mContext.getContentResolver(), Settings.System.USER_ROTATION, defaultDisplay.getRotation());
            Settings.System.putInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0);
        } else {
            Settings.System.putInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 1);
        }

        Settings.System.putInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, !orientationIsLocked() ? 1 : 0);

    } catch (Settings.SettingNotFoundException e){
        e.printStackTrace();
    }
}

public boolean orientationIsLocked(){
    if(canModifiSetting(mContext)){
        try {
            return Settings.System.getInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 0;
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }
    }
    return false;
}

public static boolean canModifiSetting(Context context){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        return Settings.System.canWrite(context);
    } else {
        return true;
    }
}

-1

usa esa línea de código

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  

en nuestro método de actividad oncreate

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.