Android: tymczasowo wyłącz zmiany orientacji w działaniu


116

Moja główna aktywność zawiera kod, który wprowadza pewne zmiany w bazie danych, których nie należy przerywać. Wykonuję ciężkie podnoszenie w innym wątku i używam okna dialogowego postępu, które ustawiłem jako nieodwołalne. Zauważyłem jednak, że jeśli obrócę telefon, ponownie uruchomię działanie, które jest NAPRAWDĘ szkodliwe dla uruchomionego procesu, i otrzymuję opcję Force Close.

To, co chcę zrobić, to programowo wyłączać zmiany orientacji ekranu do czasu zakończenia mojego procesu, kiedy to zmiany orientacji są włączone.


Ponieważ nikt nie wspomina o tej części, będziesz chciał zaimportować android.content.pm.ActivityInfo, aby użyć identyfikatora ActivityInfo.
zsalwasser


1
Zobacz: stackoverflow.com/a/32885911/2673792, aby znaleźć najlepsze rozwiązanie
Sudhir Sinha

Odpowiedzi:


165

Jak wyjaśnił Chris w swojej odpowiedzi , dzwoniąc

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

i wtedy

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

naprawdę działa jak urok ... na prawdziwych urządzeniach!

Nie myśl, że jest zepsuty podczas testowania na emulatorze, skrót ctrl + F11 ZAWSZE zmienia orientację ekranu, bez emulowania ruchów czujników.

EDYCJA: to nie była najlepsza możliwa odpowiedź. Jak wyjaśniono w komentarzach, istnieją problemy z tą metodą. Prawdziwa odpowiedź jest tutaj .


Nie mogłem zlokalizować tych stałych. Dziękuję za to.
Christopher Perry

41
Wystąpił problem z tymi metodami ... Wygląda na to, że wywołujesz setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); gdy urządzenie nie jest w domyślnej orientacji, wówczas orientacja aktywności jest natychmiast zmieniana (niszczona i odtwarzana) na domyślną orientację urządzenia. Na przykład, jeśli trzymasz telefon w orientacji poziomej, po ponownej aktywacji czujników czynność zostanie przełączona na portret i z powrotem na poziomo. Ten sam odwrotny problem z Archos A5 IT: używanie go w pozycji pionowej powoduje przełączenie czynności na poziomą i z powrotem na portret.
Kevin Gaudin

1
Prawdziwa odpowiedź na pierwotne pytanie jest dostępna: stackoverflow.com/questions/3821423/…
Kevin Gaudin

2
To nie zadziałało dla mnie. Ten jednak zadziałał: stackoverflow.com/a/10488012/1369016 Musiałem wywołać setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); lub setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); na podstawie bieżącej orientacji pobranej z metody getResources (). getConfiguration (). orientacja.
Tiago

ActivityInfo.SCREEN_ORIENTATION_SENSORnie respektuje natywnej blokady orientacji Androida. Resetowanie orientacji do ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIEDrobi.
tvkanters

43

Żadna z pozostałych odpowiedzi nie okazała się dla mnie idealna, ale oto co znalazłem.

Zablokuj orientację na bieżącą ...

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

Gdy zmiana orientacji powinna być ponownie dozwolona, ​​przywróć domyślną ...

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

9
Problem polega na tym, że Configuration.ORIENTATION_PORTRAITzostanie zwrócony w obu trybach poziomych (tj. „Normalny” i odwrócony). Więc jeśli telefon jest w odwróconej orientacji poziomej i ustawisz go na ActivityInfo.SCREEN_ORIENTATION_LANDSCAPEto, odwróci się do góry nogami. W API 9 ActivityInfo wprowadza SCREEN_ORIENTATION_REVERSE_LANDSCAPEstałą, ale nie widzę sposobu na wykrycie takiej orientacji poprzez Configurationklasę.
Błażej Czapp

1
To zadziałało. W tej odpowiedzi znajduje się odpowiedź na powyższe zastrzeżenia. stackoverflow.com/a/10453034/1223436
Zack

Zadziałało też jak urok na moje potrzeby, genialne dzięki
user2029541

39

Oto bardziej kompletne i aktualne rozwiązanie, które działa dla API 8+, działa w odwróconym pionie i poziomie oraz działa na karcie Galaxy, gdzie „naturalna” orientacja to pozioma (wywołanie w activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)celu odblokowania orientacji):

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

Świetnie działał dla mnie z tabletami i telefonami.
ScruffyFox

Jedyna poprawna odpowiedź, która działa dla mnie na wszelkiego rodzaju urządzeniach.
amdev

Zdecydowanie najlepsza odpowiedź! Możesz zrobić tę metodę statici dodać Activity activityjako parametr.
krakaj

18

Aby zarządzać także trybami odwróconej orientacji, użyłem tego kodu do ustalenia orientacji aktywności:

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

I aby ponownie pozwolić na orientację:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

17

Służy setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);do blokowania bieżącej orientacji, czy to poziomej, czy pionowej.

Służy setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);do odblokowania orientacji.


Najlepsze rozwiązanie na krótki zamek tymczasowy. Żadnego zakłócania aktualnej orientacji czujnika.
Niesamowity

2
działa na Build.VERSION.SDK_INT> = 18, dokładniejszą odpowiedź udziela tdjprog na tej stronie stackoverflow.com/a/41812971/5235263
bastami82


11

Dziękuje wszystkim. Zmodyfikowałem rozwiązanie Pilota_51, aby mieć pewność, że przywróciłem poprzedni stan. Dodałem również zmianę, aby obsługiwać ekrany inne niż poziome i nie-portretowe (ale nie testowałem tego na takim ekranie).

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

Następnie, aby go przywrócić

setRequestedOrientation(prevOrientation);

Dobra rzecz - nie wiem, dlaczego nie użyłeś switchchociaż.

Zapomniałem wyczyścić i zmienić na przełącznik po dodaniu trzeciej opcji.
ProjectJourneyman

stwierdziłem, że działa to bez konieczności pobierania bieżącej konfiguracji, jeśli nie masz dostępu do obiektu aktywności, ale tylko kontekst 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
}

Czy mógłbyś dodać wyjaśnienie do swojej odpowiedzi?
slfan

gdy masz jakieś zadania w tle, po prostu wywołaj setLockScreenOrientation (true), aby zablokować orientację i zapobiec zniszczeniu bieżącej czynności w celu jej odtworzenia. gdy upewnisz się, że te zadania zostały zakończone, wywołaj metodę setLockScreenOrientation (false).
tdjprog

2
to najlepsza odpowiedź!
Fakher

7

Oto rozwiązanie, które działa za każdym razem i zachowuje aktualną orientację ( Activity.Info.SCREEN_ORIENTATION_PORTRAITna przykład przy użyciu ustawień na 0 °, ale użytkownik może mieć orientację 180 ° jako bieżącą).

// 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
Warto wspomnieć: tylko API 18+
Dmitry Zaytsev

1

użyj, ActivityInfo.SCREEN_ORIENTATION_USERjeśli chcesz obrócić ekran tylko wtedy, gdy jest włączony na urządzeniu.


1

To działa doskonale dla mnie. Rozwiązuje problem z inną "naturalną orientacją" tabletu / telefonu;)

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

Wymyśliłem rozwiązanie, które polega na obrocie wyświetlacza, a następnie decyduje o orientacji urządzenia. Znając orientację, możemy ją zablokować i zwolnić później, gdy zajdzie taka potrzeba. To rozwiązanie może również określić, czy urządzenie jest w trybie odwróconego krajobrazu .

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

Później, jeśli potrzebujemy zwolnić orientację, możemy nazwać tę metodę:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

0

Myślę, że ten kod jest łatwiejszy do odczytania.

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

Odkryłem, że aby objąć cztery możliwości, potrzebna jest kombinacja istniejących wartości obrotu / orientacji; istnieją wartości portretowe / krajobrazowe i naturalna orientacja urządzenia. Załóżmy, że naturalna orientacja urządzeń będzie miała wartość obrotu równą 0 stopni, gdy ekran znajduje się w „naturalnej” orientacji pionowej lub poziomej. Podobnie, wartość obrotu będzie wynosić 90 stopni, gdy jest w orientacji poziomej lub pionowej (zauważ, że jest odwrotna do orientacji @ 0 stopni). Zatem wartości obrotu, które nie są 0 lub 90 stopni, będą oznaczać orientację „odwrotną”. OK, oto kod:

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

Nie podobała mi się większość odpowiedzi tutaj, ponieważ w odblokowaniu ustawili ją na NIEOKREŚLONY, w przeciwieństwie do poprzedniego stanu. ProjectJourneyman wziął to pod uwagę, co było świetne, ale wolałem kod blokujący Roya. Tak więc moja rekomendacja byłaby połączeniem tych dwóch:

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

Możesz użyć

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

użyj tej linii kodu

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  

w swojej działalności stworzyliśmy metodę

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.