Android: временно отключить изменение ориентации в действии


116

В моей основной деятельности есть код, который вносит некоторые изменения в базу данных, которые нельзя прерывать. Я делаю тяжелую работу в другом потоке и использую диалоговое окно прогресса, которое я установил как неотменяемый. Однако я заметил, что если я поверну свой телефон, он перезапустит действие, что ДЕЙСТВИТЕЛЬНО плохо для запущенного процесса, и я получаю принудительное закрытие.

Что я хочу сделать, так это программно отключить изменение ориентации экрана, пока мой процесс не завершится, после чего изменения ориентации будут включены.


Поскольку никто, похоже, не упоминает об этой части, вам нужно импортировать android.content.pm.ActivityInfo, чтобы использовать идентификатор ActivityInfo.
zsalwasser


1
Обратитесь: stackoverflow.com/a/32885911/2673792 для лучшего решения
Судхир Синха

Ответы:


165

Как объяснил Крис в своем ответе , позвонив

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

а потом

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

действительно работает как шарм ... на реальных устройствах!

Не думайте, что он сломан при тестировании на эмуляторе, сочетание клавиш ctrl + F11 ВСЕГДА меняет ориентацию экрана, без эмуляции движений датчиков.

РЕДАКТИРОВАТЬ: это был не лучший ответ. Как объясняется в комментариях, у этого метода есть проблемы. Настоящий ответ здесь .


Я не мог найти эти константы. Спасибо за это.
Кристофер Перри,

41
Проблема с этими методами ... Похоже, если вы вызовете setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); когда устройство не используется в своей ориентации по умолчанию, тогда ориентация активности немедленно изменяется (уничтожается и воссоздается) на ориентацию устройства по умолчанию. Например, на телефоне, если вы держите его в альбомной ориентации, активность переключается на портретную и обратно на альбомную при повторной активации датчиков. Та же самая противоположная проблема с Archos A5 IT: использование его в портретной ориентации приводит к переключению активности в альбомную и обратно в портретную.
Кевин Годен

1
Настоящий ответ на исходный вопрос есть: stackoverflow.com/questions/3821423/…
Кевин Годен

2
У меня это не сработало. Однако этот сработал: stackoverflow.com/a/10488012/1369016 Мне пришлось вызвать setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); или setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); на основе текущей ориентации, полученной из getResources (). getConfiguration (). Ориентация.
Tiago

ActivityInfo.SCREEN_ORIENTATION_SENSORне соблюдает блокировку ориентации Android. Сброс ориентации на ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIEDделает.
tvkanters

43

Ни один из других ответов не помог мне идеально, но вот что я обнаружил.

Зафиксировать ориентацию на текущую ...

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

Когда изменение ориентации должно быть разрешено снова, установите значение по умолчанию ...

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

9
Проблема в том, что Configuration.ORIENTATION_PORTRAITон будет возвращен в обоих ландшафтных режимах (т.е. «нормальный» и обратный). Поэтому, если телефон находится в перевернутой альбомной ориентации, и вы установите его, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPEон перевернется вверх дном. В API 9 ActivityInfo представляет SCREEN_ORIENTATION_REVERSE_LANDSCAPEконстанту, но я не вижу способа определить такую ​​ориентацию через Configurationкласс.
Błażej Czapp

1
Это сработало. Ответ на вышеуказанное беспокойство находится в этом ответе. stackoverflow.com/a/10453034/1223436
Зак

Сработал как шарм и для моих нужд, великолепное спасибо
user2029541

39

Вот более полное и современное решение, которое работает для API 8+, работает для обратной портретной и альбомной ориентации и работает на вкладке Galaxy, где «естественная» ориентация - альбомная (вызов activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)для разблокировки ориентации):

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

У меня отлично работал с планшетами и телефонами.
ScruffyFox

Единственно правильный ответ, который работает для меня на всех устройствах.
amdev

Однозначно лучший ответ! Вы можете создать этот метод staticи добавить его Activity activityв качестве параметра.
caw

18

Чтобы управлять режимами обратной ориентации, я использовал этот код для исправления ориентации активности:

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

И снова разрешить ориентацию:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

17

Используйте setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);для фиксации текущей ориентации, будь то альбомная или книжная.

Используйте setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);для разблокировки ориентации.


Лучшее решение для короткой временной блокировки. Никаких проблем с текущей ориентацией датчика.
Невероятный

2
работает над Build.VERSION.SDK_INT> = 18, более полный ответ дает tdjprog на этой странице stackoverflow.com/a/41812971/5235263
bastami82

14

Я нашел ответ. Для этого в Activity вы можете вызвать setRequestedOrientation(int)одно из значений, указанных здесь: http://developer.android.com/reference/android/R.attr.html#screenOrientation

Прежде чем я начал свою тему, я позвонил setRequestedOrientation(OFF)(OFF = носенсор), а когда поток был готов, я позвонил setRequestedOrientation(ON)(ON = датчик). Работает как шарм.


11

Спасибо всем. Я изменил решение Pilot_51, чтобы убедиться, что я вернулся в предыдущее состояние. Я также внес изменение для поддержки не альбомных и не портретных экранов (но не тестировал это на таком экране).

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

Затем восстановить его

setRequestedOrientation(prevOrientation);

Хороший материал - не знаю, почему вы не использовали switchхотя.

Забыл очистить и перейти на переключатель после того, как добавил третий вариант.
ProjectJourneyman

Я обнаружил, что это работает без необходимости получать текущую конфигурацию, если у вас нет доступа к объекту действия, а только к контексту 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
}

Не могли бы вы пояснить свой ответ?
slfan

когда у вас есть какие-то задания в фоновом режиме, просто вызовите setLockScreenOrientation (true), чтобы заблокировать ориентацию и предотвратить разрушение текущего действия для его воссоздания. когда вы убедитесь, что эти задания завершены, вызовите setLockScreenOrientation (false).
tdjprog

2
это лучший ответ!
Fakher

7

Вот решение, которое работает каждый раз и сохраняет текущую ориентацию (например, с использованием Activity.Info.SCREEN_ORIENTATION_PORTRAITзначений 0 °, но пользователь может иметь ориентацию 180 ° в качестве текущей).

// 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
Стоит упомянуть: только API 18+
Дмитрий Зайцев

1

используйте, ActivityInfo.SCREEN_ORIENTATION_USERесли вы хотите повернуть экран, только если он включен на устройстве.


1

Это работает для меня. Решает проблему с разной "естественной ориентацией" планшета / телефона;)

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

Я придумал решение, которое зависит от поворота дисплея, а затем определяет ориентацию устройства. Зная ориентацию, мы можем заблокировать ориентацию и отпустить ее позже, когда это необходимо. Это решение также может определить, находится ли устройство в режиме обратной альбомной ориентации.

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

Позже, если нам нужно освободить ориентацию, мы можем вызвать этот метод:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

0

Я думаю, что этот код легче читать.

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

Я обнаружил, что комбинация существующих значений поворота / ориентации необходима для охвата четырех возможностей; есть значения портрет / пейзаж и естественная ориентация устройства. Скажем, естественная ориентация устройств будет иметь значение поворота 0 градусов, когда экран находится в «естественной» портретной или альбомной ориентации. Точно так же будет значение поворота 90 градусов в альбомной или портретной ориентации (обратите внимание, что это противоположно ориентации @ 0 градусов). Таким образом, значения поворота, отличные от 0 или 90 градусов, будут означать «обратную» ориентацию. Хорошо, вот код:

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

Мне не понравились большинство ответов здесь, так как при разблокировке они установили НЕПРЕДВИДЕННОЕ, а не предыдущее состояние. ProjectJourneyman принял это во внимание, и это было здорово, но я предпочел код блокировки от Роя. Итак, моя рекомендация - это сочетание двух:

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

Ты можешь использовать

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

используйте эту строку кода

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  

в вашей деятельности oncreate метод

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.