Android: Menonaktifkan sementara perubahan orientasi dalam suatu Aktivitas


116

Aktivitas utama saya memiliki beberapa kode yang membuat beberapa perubahan database yang tidak boleh terganggu. Saya melakukan pekerjaan berat di utas lain, dan menggunakan dialog kemajuan yang saya tetapkan sebagai tidak dapat dibatalkan. Namun, saya perhatikan bahwa jika saya memutar ponsel saya, ponsel akan memulai ulang aktivitas yang BENAR-BENAR buruk untuk proses yang sedang berjalan, dan saya mendapatkan Tutup Paksa.

Yang ingin saya lakukan adalah menonaktifkan perubahan orientasi layar secara terprogram hingga proses saya selesai, di mana perubahan orientasi waktu diaktifkan.


Karena tampaknya tidak ada yang menyebutkan bagian ini, Anda akan ingin mengimpor android.content.pm.ActivityInfo untuk menggunakan pengenal ActivityInfo.
zsalwasser


1
Lihat: stackoverflow.com/a/32885911/2673792 untuk solusi terbaik
Sudhir Sinha

Jawaban:


165

Seperti yang dijelaskan oleh Chris dalam menjawab sendiri , menelepon

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

lalu

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

benar-benar berfungsi seperti pesona ... di perangkat nyata!

Jangan mengira itu rusak saat menguji pada emulator, pintasan ctrl + F11 SELALU mengubah orientasi layar, tanpa meniru gerakan sensor.

EDIT: ini bukan jawaban terbaik. Seperti yang dijelaskan di komentar, ada masalah dengan metode ini. Jawaban sebenarnya ada di sini .


Saya tidak dapat menemukan konstanta tersebut. Terima kasih untuk itu.
Christopher Perry

41
Ada masalah dengan metode ini ... Sepertinya jika Anda memanggil setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); bila perangkat tidak dalam penggunaan orientasi defaultnya, maka orientasi aktivitas segera diubah (dimusnahkan dan dibuat ulang) ke orientasi default perangkat. Misalnya, di ponsel, jika Anda memegangnya dalam orientasi lanskap, maka aktivitas dialihkan ke potret dan kembali ke lanskap saat mengaktifkan kembali sensor. Masalah berlawanan yang sama dengan Archos A5 IT: menggunakannya dalam potret menyebabkan aktivitas dialihkan ke lanskap dan kembali ke potret.
Kevin Gaudin

1
Jawaban sebenarnya untuk pertanyaan awal ada di sana: stackoverflow.com/questions/3821423/…
Kevin Gaudin

2
Ini tidak berhasil untuk saya. Yang satu ini berhasil: stackoverflow.com/a/10488012/1369016 Saya harus memanggil setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); atau setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); berdasarkan orientasi saat ini yang diambil dari orientasi getResources (). getConfiguration ().
Tiago

ActivityInfo.SCREEN_ORIENTATION_SENSORtidak menghormati kunci orientasi asli Android. Mengatur ulang orientasi ke ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIEDlakukan.
tvkanters

43

Tidak ada jawaban lain yang berhasil dengan sempurna untuk saya, tetapi inilah yang saya temukan.

Kunci orientasi ke arus ...

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

Saat mengubah orientasi harus diizinkan lagi, setel kembali ke default ...

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

9
Masalahnya adalah yang Configuration.ORIENTATION_PORTRAITakan dikembalikan dalam kedua mode lanskap (yaitu 'normal', dan dibalik). Jadi jika ponsel dalam orientasi lanskap terbalik dan Anda mengaturnya, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPEponsel akan terbalik. Dalam API 9, ActivityInfo memperkenalkan SCREEN_ORIENTATION_REVERSE_LANDSCAPEkonstanta, tetapi saya tidak melihat cara untuk mendeteksi orientasi semacam itu melalui Configurationkelas.
Błażej Czapp

1
Ini berhasil. Jawaban atas keprihatinan di atas terletak pada jawaban ini. stackoverflow.com/a/10453034/1223436
Zack

Bekerja seperti jimat untuk kebutuhan saya juga, terima kasih yang luar biasa
pengguna2029541

39

Berikut adalah solusi yang lebih lengkap dan terkini yang berfungsi untuk API 8+, berfungsi untuk potret terbalik dan lanskap, dan berfungsi pada tab Galaxy di mana orientasi "alami" adalah lanskap (panggil activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)untuk membuka kunci orientasi):

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

Sangat cocok untuk saya dengan tablet dan ponsel.
ScruffyFox

Satu-satunya jawaban yang benar yang berfungsi pada semua jenis perangkat untuk saya.
amdev

Pasti jawaban terbaik! Anda dapat membuat metode ini staticdan menambahkannya Activity activitysebagai parameter.
gak

18

Untuk mengelola juga mode orientasi terbalik, saya telah menggunakan kode itu untuk memperbaiki orientasi aktivitas:

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

Dan untuk memungkinkan lagi orientasi:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

17

Gunakan setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);untuk mengunci orientasi saat ini apakah itu lanskap atau potret.

Gunakan setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);untuk membuka kunci orientasi.


Solusi terbaik untuk kunci sementara pendek. Tidak mengotak-atik orientasi sensor saat ini.
Jan

2
bekerja pada Build.VERSION.SDK_INT> = 18, jawaban yang lebih lengkap diberikan oleh tdjprog di halaman ini stackoverflow.com/a/41812971/5235263
bastami82


11

Terima kasih semuanya. Saya memodifikasi solusi Pilot_51, untuk memastikan saya mengembalikan ke keadaan sebelumnya. Saya juga melakukan perubahan untuk mendukung layar non-lanskap dan non-potret (tetapi belum mengujinya pada layar seperti itu).

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

Kemudian untuk memulihkannya

setRequestedOrientation(prevOrientation);

Barang bagus - tidak yakin mengapa Anda tidak menggunakan a switch.

Lupa membersihkan dan beralih ke sakelar setelah saya menambahkan opsi ketiga.
ProjectJourneyman

saya menemukan ini berfungsi tanpa harus mendapatkan konfigurasi saat ini jika Anda tidak memiliki akses ke objek aktivitas tetapi hanya konteks 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
}

Bisakah Anda menambahkan penjelasan pada jawaban Anda?
slfan

bila Anda memiliki beberapa pekerjaan di latar belakang, cukup panggil setLockScreenOrientation (true) untuk mengunci orientasi dan mencegah penghancuran aktivitas saat ini untuk membuatnya kembali. ketika Anda memastikan bahwa pekerjaan ini telah selesai, panggil setLockScreenOrientation (false).
tdjprog

2
ini adalah jawaban terbaik!
Fakher

7

Berikut adalah solusi yang bekerja setiap saat dan mempertahankan orientasi saat ini (menggunakan Activity.Info.SCREEN_ORIENTATION_PORTRAITset ke 0 ° misalnya, tetapi pengguna dapat memiliki orientasi 180 ° seperti yang sekarang).

// 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
Layak untuk disebutkan: Hanya API 18+
Dmitry Zaytsev

1

gunakan ActivityInfo.SCREEN_ORIENTATION_USERjika Anda ingin memutar layar hanya jika diaktifkan pada perangkat.


1

Ini bekerja dengan sempurna bagi saya. Ini memecahkan masalah dengan "orientasi alami" tablet / ponsel yang berbeda;)

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

Saya telah menemukan solusi yang bergantung pada rotasi layar dan kemudian memutuskan orientasi perangkat. Dari mengetahui orientasi kita dapat mengunci orientasi dan melepaskannya nanti saat diperlukan. Solusi ini juga dapat menentukan apakah perangkat dalam mode lanskap terbalik .

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

Kemudian jika kita perlu melepaskan orientasi kita dapat memanggil metode ini:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

0

Saya rasa kode ini lebih mudah dibaca.

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

Saya telah menemukan kombinasi nilai rotasi / orientasi yang ada diperlukan untuk mencakup empat kemungkinan; ada nilai potret / lanskap dan orientasi alami perangkat. Misalkan, orientasi alami perangkat akan memiliki nilai rotasi 0 derajat saat layar dalam orientasi potret atau lanskap "alami". Demikian pula, akan ada nilai rotasi 90 derajat saat dalam lanskap atau potret (perhatikan kebalikan dari orientasi @ 0 derajat). Jadi nilai rotasi yang bukan 0 atau 90 derajat akan menunjukkan orientasi "Terbalik". Oke, berikut beberapa kodenya:

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

Saya tidak suka sebagian besar jawaban di sini, karena dalam pembukaan kunci mereka mengaturnya ke UNSPECIFIED sebagai lawan dari keadaan sebelumnya. ProjectJourneyman memang memperhitungkannya, dan itu bagus, tapi saya lebih suka kode penguncian dari Roy. Jadi, rekomendasi saya adalah campuran keduanya:

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

Kamu bisa memakai

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

gunakan baris kode itu

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  

dalam metode pembuatan aktivitas Anda

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.