Android: тимчасово відключити зміни орієнтації в діяльності


116

Моя основна діяльність має деякий код, який вносить деякі зміни в базу даних, які не слід переривати. Я займаюся важким підйомом в іншій нитці і використовую діалог прогресу, який я встановив як невідмінюваний. Однак я помітив, що якщо я повертаю телефон, то він відновлює активність, яка дійсно погана для запущеного процесу, і я отримую силу закриття.

Що я хочу зробити, - це програмно відключити зміни орієнтації екрана, поки мій процес не завершиться, і в цей час зміни орієнтації включені.


Оскільки, здається, ніхто не згадує цю частину, вам потрібно буде імпортувати android.content.pm.ActivityInfo, щоб використовувати ідентифікатор ActivityInfo.
zsalwasser


1
Посилайтеся: stackoverflow.com/a/32885911/2673792 для найкращого рішення
Sudhir Sinha

Відповіді:


165

Як пояснив Кріс у своїй самовідповіді , дзвонив

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

і потім

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

справді працює як шарм ... на реальних пристроях!

Не думайте, що вона порушена під час тестування на емуляторі, ярлик ctrl + F11 ЗАВЖДИ змінює орієнтацію екрана, не емілюючи переміщення датчиків.

EDIT: це була не найкраща можлива відповідь. Як пояснено в коментарях, з цим методом є проблеми. Справжня відповідь тут .


Я не міг знайти цих констант. Дякую за це.
Крістофер Перрі

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 ().
Тіаго

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клас.
Блажей Чапп

1
Це спрацювало. Відповідь на вищезазначене занепокоєння міститься у цій відповіді. stackoverflow.com/a/10453034/1223436
Зак

Працював як шарм і для моїх потреб, блискучий спасибі
користувач2029541

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як параметр.
каре

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

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

Перед тим, як setRequestedOrientation(OFF)запустити нитку, я зателефонував (OFF = nosensor), і коли нитка була виконана, я подзвонив 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
це найкраща відповідь!
Фахер

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.