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.