Android: disabilita temporaneamente i cambiamenti di orientamento in un'attività


116

La mia attività principale ha del codice che apporta alcune modifiche al database che non dovrebbero essere interrotte. Sto facendo il lavoro pesante in un altro thread e utilizzando una finestra di dialogo di avanzamento che ho impostato come non cancellabile. Tuttavia, ho notato che se ruoto il mio telefono riavvia l'attività che è DAVVERO dannosa per il processo in esecuzione, e ottengo una chiusura forzata.

Quello che voglio fare è disabilitare programmaticamente le modifiche all'orientamento dello schermo fino al completamento del mio processo, momento in cui le modifiche all'orientamento sono abilitate.


Poiché nessuno sembra menzionare questa parte, vorrai importare android.content.pm.ActivityInfo per utilizzare l'identificatore ActivityInfo.
zsalwasser


1
Fare riferimento a: stackoverflow.com/a/32885911/2673792 per la migliore soluzione
Sudhir Sinha

Risposte:


165

Come spiegato da Chris nella sua auto-risposta , chiamando

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

e poi

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

funziona davvero come un fascino ... su dispositivi reali!

Non pensare che sia rotto durante il test sull'emulatore, la scorciatoia ctrl + F11 cambia SEMPRE l'orientamento dello schermo, senza emulare i movimenti dei sensori.

EDIT: questa non era la migliore risposta possibile. Come spiegato nei commenti, ci sono problemi con questo metodo. La vera risposta è qui .


Non sono riuscito a localizzare quelle costanti. Grazie per quello.
Christopher Perry,

41
C'è un problema con questi metodi ... Sembra che se chiami setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); quando il dispositivo non utilizza l'orientamento predefinito, l'orientamento dell'attività viene immediatamente modificato (distrutto e ricreato) nell'orientamento predefinito del dispositivo. Ad esempio, su un telefono, se lo tieni in orientamento orizzontale, l'attività passa in verticale e di nuovo in orizzontale quando si riattivano i sensori. Lo stesso problema opposto con un Archos A5 IT: utilizzarlo in verticale fa sì che l'attività venga spostata in orizzontale e di nuovo in verticale.
Kevin Gaudin

1
La vera risposta alla domanda originale è lì: stackoverflow.com/questions/3821423/…
Kevin Gaudin

2
Questo non ha funzionato per me. Questo però ha funzionato: stackoverflow.com/a/10488012/1369016 ho dovuto chiamare setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); o setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); in base all'orientamento corrente recuperato da getResources (). getConfiguration (). Orientamento.
Tiago

ActivityInfo.SCREEN_ORIENTATION_SENSORnon rispetta il blocco dell'orientamento nativo di Android. Reimpostare l'orientamento su ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIEDfa.
tvkanters

43

Nessuna delle altre risposte ha funzionato perfettamente per me, ma ecco cosa ho scoperto che fa.

Blocca orientamento su corrente ...

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

Quando si dovrebbe consentire nuovamente la modifica dell'orientamento, ripristinare l'impostazione predefinita ...

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

9
Il problema con questo è che Configuration.ORIENTATION_PORTRAITverrà restituito in entrambe le modalità landscape (cioè "normale" e invertito). Quindi, se il telefono è in orientamento orizzontale invertito e lo imposti ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, verrà capovolto. Nell'API 9, ActivityInfo introduce la SCREEN_ORIENTATION_REVERSE_LANDSCAPEcostante, ma non vedo un modo per rilevare tale orientamento attraverso la Configurationclasse.
Błażej Czapp

1
Questo ha funzionato. La risposta alla preoccupazione di cui sopra si trova in questa risposta. stackoverflow.com/a/10453034/1223436
Zack

Ha funzionato alla
perfezione

39

Ecco una soluzione più completa e aggiornata che funziona per API 8+, funziona per ritratto e paesaggio invertiti e funziona su una scheda Galaxy in cui l'orientamento "naturale" è orizzontale (chiama activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)per sbloccare l'orientamento):

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

Ha funzionato alla grande per me con tablet e telefoni.
ScruffyFox

L'unica risposta corretta che funziona su tutti i tipi di dispositivi per me.
amdev

Sicuramente la migliore risposta! Puoi creare questo metodo statice aggiungere Activity activitycome parametro.
caw

18

Per poter gestire anche le modalità di orientamento inverso, ho utilizzato quel codice per correggere l'orientamento dell'attività:

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

E per consentire nuovamente l'orientamento:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

17

Utilizzare setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);per bloccare l'orientamento corrente, sia orizzontale che verticale.

Utilizzare setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);per sbloccare l'orientamento.


La migliore soluzione per un breve blocco temporaneo. Nessun problema con l'orientamento corrente del sensore.
L'incredibile gennaio

2
funziona su Build.VERSION.SDK_INT> = 18, risposta più completa è data da tdjprog in questa pagina stackoverflow.com/a/41812971/5235263
bastami82


11

Ringrazia tutti. Ho modificato la soluzione di Pilot_51, per assicurarmi di aver ripristinato lo stato precedente. Ho anche apportato una modifica per supportare schermi non orizzontali e non verticali (ma non l'ho testato su uno schermo del genere).

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

Quindi ripristinarlo

setRequestedOrientation(prevOrientation);

Roba buona - non sono sicuro del motivo per cui non hai usato un switchperò.

Ho dimenticato di pulire e passare a un interruttore dopo aver aggiunto la terza opzione.
ProjectJourneyman

ho trovato che funziona senza dover ottenere la configurazione corrente se non si ha accesso all'oggetto attività ma solo al contesto 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
}

Potresti aggiungere qualche spiegazione alla tua risposta?
slfan

quando hai alcuni lavori in background, chiama semplicemente setLockScreenOrientation (true) per bloccare l'orientamento e impedire la distruzione dell'attività corrente per ricrearla. quando ci si assicura che questi lavori siano terminati, chiamare setLockScreenOrientation (false).
tdjprog

2
questa è la risposta migliore!
Fakher

7

Ecco una soluzione che funziona ogni volta e preserva l'orientamento corrente (usando i Activity.Info.SCREEN_ORIENTATION_PORTRAITset a 0 ° per esempio, ma l'utente può avere un orientamento di 180 ° come quello corrente).

// 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
Da segnalare: solo API 18+
Dmitry Zaytsev

1

utilizzare ActivityInfo.SCREEN_ORIENTATION_USERse si desidera ruotare lo schermo solo se è abilitato sul dispositivo.


1

Questo funziona perfettamente per me. Risolve problemi con il diverso "orientamento naturale" di tablet / telefono;)

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

Ho trovato una soluzione che dipende dalla rotazione del display e poi decide l'orientamento del dispositivo. Conoscendo l'orientamento possiamo bloccare l'orientamento e rilasciarlo in un secondo momento quando necessario. Questa soluzione può anche determinare se il dispositivo è in modalità orizzontale inversa .

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

Quindi in seguito, se dobbiamo rilasciare l'orientamento, possiamo chiamare questo metodo:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

0

Penso che questo codice sia più facile da leggere.

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

Ho scoperto che una combinazione di valori di rotazione / orientamento esistenti è necessaria per coprire le quattro possibilità; ci sono i valori verticale / orizzontale e l'orientamento naturale del dispositivo. Diciamo che l'orientamento naturale dei dispositivi avrà un valore di rotazione di 0 gradi quando lo schermo è nel suo orientamento "naturale" verticale o orizzontale. Allo stesso modo, ci sarà un valore di rotazione di 90 gradi quando è in orizzontale o verticale (notare che è opposto all'orientamento a 0 gradi). Quindi i valori di rotazione che non sono 0 o 90 gradi implicheranno l'orientamento "Reverse". Ok, ecco un po 'di codice:

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

Non mi sono piaciute la maggior parte delle risposte qui, poiché nello sblocco lo hanno impostato su NON specificato rispetto allo stato precedente. ProjectJourneyman ne ha tenuto conto, il che è stato fantastico, ma ho preferito il codice di blocco di Roy. Quindi, la mia raccomandazione sarebbe un mix dei due:

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

Puoi usare

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 quella riga di codice

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  

nella tua attività oncreate metodo

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.