Android: désactiver temporairement les changements d'orientation dans une activité


116

Mon activité principale a du code qui apporte des modifications à la base de données qui ne doivent pas être interrompues. Je fais le gros du travail dans un autre thread et j'utilise une boîte de dialogue de progression que j'ai définie comme non annulable. Cependant, j'ai remarqué que si je fais pivoter mon téléphone, il redémarre l'activité, ce qui est VRAIMENT mauvais pour le processus en cours d'exécution, et j'obtiens une fermeture forcée.

Ce que je veux faire, c'est désactiver par programme les changements d'orientation de l'écran jusqu'à ce que mon processus se termine, moment auquel les changements d'orientation sont activés.


Comme personne ne semble mentionner cette partie, vous allez vouloir importer android.content.pm.ActivityInfo afin d'utiliser l'identifiant ActivityInfo.
zsalwasser


1
Référez-vous: stackoverflow.com/a/32885911/2673792 pour la meilleure solution
Sudhir Sinha

Réponses:


165

Comme l'explique Chris dans sa réponse personnelle , appelant

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

puis

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

fonctionne vraiment comme du charme ... sur de vrais appareils!

Ne pensez pas qu'il est cassé lors du test sur l'émulateur, le raccourci ctrl + F11 change TOUJOURS l'orientation de l'écran, sans émuler les mouvements des capteurs.

EDIT: ce n'était pas la meilleure réponse possible. Comme expliqué dans les commentaires, cette méthode pose des problèmes. La vraie réponse est ici .


Je n'ai pas pu localiser ces constantes. Merci pour ça.
Christopher Perry

41
Il y a un problème avec ces méthodes ... Il semble que vous appeliez setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); lorsque le périphérique n'est pas dans son orientation par défaut, l'orientation de l'activité est immédiatement modifiée (détruite et recréée) à l'orientation par défaut du périphérique. Par exemple, sur un téléphone, si vous le maintenez en orientation paysage, l'activité passe en portrait et revient en paysage lors de la réactivation des capteurs. Le même problème inverse avec un Archos A5 IT: l'utiliser en portrait fait basculer l'activité en paysage et revenir en portrait.
Kevin Gaudin

1
La vraie réponse à la question initiale est là: stackoverflow.com/questions/3821423/…
Kevin Gaudin

2
Cela n'a pas fonctionné pour moi. Celui-ci a cependant fonctionné: stackoverflow.com/a/10488012/1369016 J'ai dû appeler setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); ou setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); basé sur l'orientation actuelle extraite de getResources (). getConfiguration (). orientation.
Tiago

ActivityInfo.SCREEN_ORIENTATION_SENSORne respecte pas le verrou d'orientation natif d'Android. Réinitialisation de l'orientation à ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIEDfait.
tvkanters

43

Aucune des autres réponses n'a parfaitement fonctionné pour moi, mais voici ce que j'ai trouvé que cela fait.

Verrouiller l'orientation sur le courant ...

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

Lorsque le changement d'orientation doit être autorisé à nouveau, réinitialiser la valeur par défaut ...

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

9
Le problème avec ceci est qu'il Configuration.ORIENTATION_PORTRAITsera renvoyé dans les deux modes paysage (c'est-à-dire «normal» et inversé). Donc, si le téléphone est en orientation paysage inversée et que vous le réglez, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPEil se retournera. Dans l'API 9, ActivityInfo introduit une SCREEN_ORIENTATION_REVERSE_LANDSCAPEconstante, mais je ne vois pas de moyen de détecter une telle orientation à travers la Configurationclasse.
Błażej Czapp

1
Cela a fonctionné. La réponse à la préoccupation ci-dessus se trouve dans cette réponse. stackoverflow.com/a/10453034/1223436
Zack

A travaillé comme un charme pour mes besoins aussi, merci génial
user2029541

39

Voici une solution plus complète et à jour qui fonctionne pour l'API 8+, fonctionne pour le portrait inversé et le paysage, et fonctionne sur un onglet Galaxy où l'orientation «naturelle» est paysage (appelez activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)pour déverrouiller l'orientation):

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

A très bien fonctionné pour moi avec une tablette et des téléphones.
ScruffyFox

La seule réponse correcte qui fonctionne sur tout type d'appareil pour moi.
amdev

Certainement la meilleure réponse! Vous pouvez créer cette méthode staticet l'ajouter en Activity activitytant que paramètre.
caw

18

Afin de gérer également les modes d'orientation inversée, j'ai utilisé ce code pour fixer l'orientation de l'activité:

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

Et pour permettre à nouveau l'orientation:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

17

Utilisation setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); pour verrouiller l'orientation actuelle, qu'elle soit paysage ou portrait.

Utilisez setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);pour déverrouiller l'orientation.


Meilleure solution pour un verrou temporaire court. Pas de dérangement avec l'orientation actuelle du capteur.
L'incroyable janvier

2
fonctionne sur Build.VERSION.SDK_INT> = 18, une réponse plus complète est donnée par tdjprog dans cette page stackoverflow.com/a/41812971/5235263
bastami82


11

Merci a tous. J'ai modifié la solution de Pilot_51, pour m'assurer de restaurer l'état précédent. J'ai également apporté un changement pour prendre en charge les écrans non-paysage et non-portrait (mais je ne l'ai pas testé sur un tel écran).

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

Puis pour le restaurer

setRequestedOrientation(prevOrientation);

Bon truc - je ne sais pas pourquoi vous ne l'avez pas utilisé switch.

J'ai oublié de nettoyer et de passer à un commutateur après avoir ajouté la troisième option.
ProjectJourneyman

J'ai trouvé que cela fonctionne sans avoir à obtenir la configuration actuelle si vous n'avez pas accès à l'objet d'activité mais uniquement au contexte 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
}

Pourriez-vous s'il vous plaît ajouter quelques explications à votre réponse?
slfan

lorsque vous avez des travaux en arrière-plan, il suffit d'appeler setLockScreenOrientation (true) pour verrouiller l'orientation et éviter de détruire l'activité en cours afin de la recréer. lorsque vous vous assurez que ces travaux sont terminés, appelez setLockScreenOrientation (false).
tdjprog

2
C'est la meilleure réponse !
Fakher

7

Voici une solution qui fonctionne à chaque fois et préserve l'orientation actuelle (en utilisant des Activity.Info.SCREEN_ORIENTATION_PORTRAITensembles à 0 ° par exemple, mais l'utilisateur peut avoir une orientation à 180 ° comme celle actuelle).

// 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
À mentionner: API 18+ uniquement
Dmitry Zaytsev

1

à utiliser ActivityInfo.SCREEN_ORIENTATION_USERsi vous souhaitez faire pivoter l'écran uniquement s'il est activé sur l'appareil.


1

Cela fonctionne parfaitement pour moi. Il résout le problème avec une "orientation naturelle" différente de la tablette / téléphone;)

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

J'ai trouvé une solution qui dépend de la rotation de l'affichage et décide ensuite de l'orientation de l'appareil. En connaissant l'orientation, nous pouvons verrouiller l'orientation et la libérer plus tard en cas de besoin. Cette solution permet également de déterminer si l'appareil est en mode paysage inversé .

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

Puis plus tard, si nous devons libérer l'orientation, nous pouvons appeler cette méthode:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

0

Je pense que ce code est plus facile à lire.

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

J'ai trouvé qu'une combinaison de valeurs de rotation / orientation existantes est nécessaire pour couvrir les quatre possibilités; il y a les valeurs portrait / paysage et l'orientation naturelle de l'appareil. Disons que l'orientation naturelle des appareils aura une valeur de rotation de 0 degré lorsque l'écran est dans son orientation portrait ou paysage "naturelle". De même, il y aura une valeur de rotation de 90 degrés quand il est en paysage ou portrait (notez qu'il est opposé à l'orientation à 0 degrés). Ainsi, les valeurs de rotation qui ne sont pas 0 ou 90 degrés impliqueront une orientation "Inversée". Ok, voici un code:

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

Je n'ai pas aimé la plupart des réponses ici, car dans le déverrouillage, ils l'ont défini sur NON SPÉCIFIÉ par opposition à l'état précédent. ProjectJourneyman en a tenu compte, ce qui était super, mais j'ai préféré le code de verrouillage de Roy. Donc, ma recommandation serait un mélange des deux:

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

Vous pouvez utiliser

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

utiliser cette ligne de code

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  

dans votre activité oncreate méthode

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.