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.