Android: izinkan potret dan lansekap untuk tablet, tapi paksa potret di ponsel?

191

Saya ingin tablet dapat ditampilkan dalam potret dan lanskap (sw600dp atau lebih tinggi), tetapi ponsel dibatasi hanya untuk potret. Saya tidak dapat menemukan cara untuk memilih orientasi secara kondisional. Ada saran?

Kenny Wyland
sumber
Salah satu caranya adalah TIDAK untuk merancang tata letak lanskap untuk ponsel, seperti dalam menggunakan folder layout-landdi dalam res.
Ghost
12
Itu hanya akan menyebabkan tata letak potret ditampilkan dalam lanskap. Ini sebenarnya tidak akan mencegah telepon dari berputar ke lanskap.
Radley

Jawaban:

446

Berikut cara yang baik menggunakan sumber daya dan ukuran kualifikasi .

Masukkan sumber bool ini dalam res / nilai sebagai bools.xml atau apa pun (nama file tidak masalah di sini):

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <bool name="portrait_only">true</bool>
    </resources>

Letakkan ini di res / values-sw600dp dan res / values-xlarge:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <bool name="portrait_only">false</bool>
    </resources>

Lihat jawaban tambahan ini untuk membantu menambahkan direktori dan file ini di Android Studio.

Kemudian, dalam metode onCreate dari Aktivitas Anda, Anda dapat melakukan ini:

    if(getResources().getBoolean(R.bool.portrait_only)){
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }

Perangkat yang lebih dari 600 dp dalam arah lebar terkecil, atau x-besar pada perangkat pra-Android 3.2 (tablet, pada dasarnya) akan berperilaku seperti biasa, berdasarkan sensor dan rotasi yang dikunci pengguna, dll . Segala sesuatu yang lain (telepon, cukup banyak) akan menjadi potret saja.

Brian Christensen
sumber
1
Apakah saya perlu menggunakan xlargejuga atau bisakah saya menggunakan sw600dp? Mungkin tidak ada tablet yang menjalankan <3.2 hari ini.
theblang
7
Nah, ini berpotensi memulai kembali aktivitas ketika dimulai dalam lansekap, lihat developer.android.com/reference/android/app/…
Bondax
1
@Bondax Komentar itu hanya berlaku "Jika aktivitas saat ini di latar depan atau berdampak pada orientasi layar" yang tidak dapat terjadi karena kita berada di onCreate pada saat ini.
Brian Christensen
1
@BrianChristensen Saya mengamati memulai kembali suatu kegiatan ketika mengatur orientasi yang diminta di onCreate(). Ketika saya memindahkan panggilan ke setRequestedOrientation()posisi yang berbeda dalam waktu dan konteks, restart tidak terjadi lagi.
Bondax
8
jika saya memulai aplikasi dalam mode lansekap, ia masih menampilkan mode lansekap untuk sesaat.
最 白 目
29

Anda dapat mencoba cara ini terlebih dahulu untuk mendapatkan ukuran layar perangkat

if ((getResources().getConfiguration().screenLayout &      Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) {     
    Toast.makeText(this, "Large screen",Toast.LENGTH_LONG).show();

}
else if ((getResources().getConfiguration().screenLayout &      Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_NORMAL) {     
    Toast.makeText(this, "Normal sized screen" , Toast.LENGTH_LONG).show();

} 
else if ((getResources().getConfiguration().screenLayout &      Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_SMALL) {     
    Toast.makeText(this, "Small sized screen" , Toast.LENGTH_LONG).show();
}
else {
    Toast.makeText(this, "Screen size is neither large, normal or small" , Toast.LENGTH_LONG).show();
}

dan kemudian mengatur orientasi sesuai dengan itu

setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Avi Kumar Manku
sumber
4
Metode apa yang harus saya masukkan metode setRequestedOrientation ()? Setelah onCreate dimulai, ia telah memilih orientasi yang diinginkan.
Kenny Wyland
kenny periksa ini saya pikir ini mungkin membantu Anda stackoverflow.com/questions/2833474/...
Avi Kumar Manku
Saya melihat jawaban ini dibatalkan, tetapi saya tidak yakin itu menyelesaikan masalah. Configurationmemberikan screenLayoutinformasi - DPI. Sedangkan pertanyaannya terkait dengan ukuran layar perangkat fisik - ponsel VS tablet. Artinya, Anda dapat memiliki Configuration.SCREENLAYOUT_SIZE_NORMALdan itu akan menjadi tablet MDPI.
nightfixed
saya menghadapi masalah stackoverflow.com/questions/42172864/…
Aditya Vyas-Lakhan
10

Tambahan untuk jawaban yang diterima

Anda dapat melakukan langkah-langkah berikut di Android Studio untuk menambahkan res/values-sw600dpdan res/values-largedirektori dengan bools.xmlfile mereka .

nilai-sw600dp

Pertama-tama, dari tab Project pilih filter Project (bukan Android) di navigator.

masukkan deskripsi gambar di sini

Kemudian klik kanan app/src/main/resdirektori tersebut. Pilih Baru > Direktori Sumber Daya Android .

Pilih Lebar Layar Terkecil , lalu tekan tombol >> .

masukkan deskripsi gambar di sini

Ketik 600lebar layar terkecil. Nama direktori akan dibuat secara otomatis. Katakan OK

masukkan deskripsi gambar di sini

Kemudian klik kanan pada file yang baru dibuat values-sw600dp. Pilih Baru > File sumber daya Nilai . Ketikkan boolsnama.

nilai-besar

Menambahkan values-largedirektori hanya diperlukan jika Anda mendukung pra Android 3.2 (API level 13). Kalau tidak, Anda dapat melewati langkah ini. The values-largedirektori sesuai dengan values-sw600dp. ( values-xlargesesuai dengan values-sw720dp.)

Untuk membuat values-largedirektori, ikuti langkah-langkah yang sama seperti di atas, tetapi dalam hal ini pilih Ukuran daripada Lebar Layar Terkecil. Pilih Besar . Nama direktori akan dibuat secara otomatis.

masukkan deskripsi gambar di sini

Klik kanan direktori seperti sebelumnya untuk membuat bools.xmlfile.

Suragch
sumber
2
Beri tahu saya jika ini tidak berhasil dan saya akan memperbaikinya. Ini berhasil untuk saya. Saya mendapat satu downvote tetapi tidak ada komentar jadi saya tidak tahu harus memperbaikinya.
Suragch
9

Begini cara saya melakukannya (terinspirasi oleh http://androidblogger.blogspot.com/2011/08/orientation-for-both-phones-and-tablets.html ):

Di AndroidManifest.xml, untuk setiap aktivitas Anda ingin dapat mengubah antara potret dan lanskap (pastikan Anda menambahkan screenSize - Anda tidak membutuhkannya!) Anda tidak perlu mengatur orientasi layar di sini. :

android:configChanges="keyboardHidden|orientation|screenSize"

Metode untuk ditambahkan di setiap Aktivitas:

public static boolean isXLargeScreen(Context context) {
    return (context.getResources().getConfiguration().screenLayout
    & Configuration.SCREENLAYOUT_SIZE_MASK)
    >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
} 

dan: (jika Anda tidak menimpa metode ini, aplikasi akan memanggil onCreate () saat mengubah orientasi)

@Override
public void onConfigurationChanged (Configuration newConfig)
{       
    super.onConfigurationChanged(newConfig);

    if (!isXLargeScreen(getApplicationContext()) ) {            
        return; //keep in portrait mode if a phone      
    }

    //I set background images for landscape and portrait here
}

Di onCreate () dari setiap Kegiatan:

if (!isXLargeScreen(getApplicationContext())) { //set phones to portrait; 
   setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);            
}
else {
  //I set background images here depending on portrait or landscape orientation 
}

Satu-satunya hal yang saya tidak tahu adalah bagaimana cara mendapatkan aplikasi untuk mengubah file tata letak ketika beralih dari landscape ke portrait atau sebaliknya. Saya menganggap jawabannya adalah melakukan sesuatu yang mirip dengan apa yang dilakukan tautan di atas, tetapi saya tidak bisa membuatnya bekerja untuk saya - itu menghapus semua data saya. Tetapi jika Anda memiliki aplikasi yang cukup sederhana sehingga Anda memiliki file tata letak yang sama untuk potret dan lansekap, ini seharusnya berfungsi.

Ginny
sumber
2
letakkan layout lansekap di folder layout-land Anda
radley
Anda akan mendapatkan pengecualian jika Anda tidak menelepon super onConfigurationChanged
RominaV
8

Mengikuti jawaban Ginny , saya pikir cara yang paling dapat diandalkan untuk melakukannya adalah sebagai berikut:

Seperti dijelaskan di sini , letakkan boolean di sumber sw sw00dp Itu harus memiliki awalan sw kalau tidak itu tidak akan berfungsi dengan baik:

dalam res / values-sw600dp / dimens.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isTablet">true</bool>
</resources>

dalam res / values ​​/ dimens.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isTablet">false</bool>
</resources>

Kemudian buat metode untuk mengambil boolean itu:

public class ViewUtils {
    public static boolean isTablet(Context context){
        return context.getResources().getBoolean(R.bool.isTablet);
    }
}

Dan aktivitas dasar untuk memperluas dari aktivitas di mana Anda menginginkan perilaku ini:

public abstract class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (!ViewUtils.isTablet(this)) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
    }
}

Jadi setiap aktivitas akan memperluas BaseActivity:

public class LoginActivity extends BaseActivity //....

Penting : meskipun Anda memperluas dari BaseActivity, Anda harus menambahkan baris android:configChanges="orientation|screenSize"ke masing-masing Activitydi AndroidManifest.xml Anda:

    <activity
        android:name=".login.LoginActivity"
        android:configChanges="orientation|screenSize">
    </activity>
RominaV
sumber
5

Yah, ini agak terlambat, tetapi, ini adalah XML-Only tetapi solusi peretasan yang tidak menciptakan kembali aktivitas seperti setRequestedOrientationhalnya jika harus mengubah orientasi:

https://stackoverflow.com/a/27015879/1281930

gosong
sumber
1
Tidak berfungsi, tablet selalu mengambil orientasi ponsel. Rupanya android: screenOrientation diatur tepat sekali untuk semua aktivitas dalam manifes, sebelum pengubah sumber daya apa pun diterapkan.
0101100101
2

Mengikuti jawaban yang diterima , saya menambahkan file kotlin dengan solusinya semoga membantu seseorang

Masukkan sumber bool ini res/valuessebagai bools.xml atau apa pun (nama file tidak penting di sini):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="portrait_only">true</bool>
</resources>

Masukkan ini res/values-sw600dpdan res/values-sw600dp-land:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="portrait_only">false</bool>
</resources>

Kemudian, tambahkan di bawah garis dalam aktivitas atau fragmentvity Anda

class MyActivity : Activity() {

    @SuppressLint("SourceLockedOrientationActivity")
    override fun onCreate(savedInstanceState: Bundle?) {
        if (resources.getBoolean(R.bool.portrait_only)) {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        }
        super.onCreate(savedInstanceState)
    }

    @SuppressLint("SourceLockedOrientationActivity")
    override fun onConfigurationChanged(newConfig: Configuration) {
        if (resources.getBoolean(R.bool.portrait_only)) {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        }
        super.onConfigurationChanged(newConfig)
    }
}
Rahul
sumber
1

Solusi lain tidak berhasil untuk saya. Saya masih memiliki beberapa masalah orientasi aneh dengan dialog dan masalah rekreasi. Solusi saya adalah memperluas Aktivitas, memaksanya sebagai potret dalam manifes.

Contoh:

public class MainActivityPhone extends MainActivity {}

manifes.xml:

        <activity
        android:screenOrientation="portrait"
        android:name=".MainActivityPhone"
        android:theme="@style/AppTheme.NoActionBar" />

dalam kegiatan splashcreen:

    Intent i = null;
    boolean isTablet = getResources().getBoolean(R.bool.is_tablet);
    if (!isTablet)
        i = new Intent(this, MainActivityPhone.class);
    else
        i = new Intent(this, MainActivity.class);
    startActivity(i);
mengoni
sumber
0

Pertanyaan lama yang saya tahu. Untuk menjalankan aplikasi Anda selalu dalam mode potret bahkan ketika orientasi mungkin atau sedang ditukar dll (misalnya pada tablet) Saya merancang fungsi ini yang digunakan untuk mengatur perangkat dalam orientasi yang benar tanpa perlu tahu bagaimana potret dan lansekap fitur disusun pada perangkat.

   private void initActivityScreenOrientPortrait()
    {
        // Avoid screen rotations (use the manifests android:screenOrientation setting)
        // Set this to nosensor or potrait

        // Set window fullscreen
        this.activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        DisplayMetrics metrics = new DisplayMetrics();
        this.activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);

         // Test if it is VISUAL in portrait mode by simply checking it's size
        boolean bIsVisualPortrait = ( metrics.heightPixels >= metrics.widthPixels ); 

        if( !bIsVisualPortrait )
        { 
            // Swap the orientation to match the VISUAL portrait mode
            if( this.activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT )
             { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); }
            else { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ); }
        }
        else { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); }

    }

Bekerja seperti pesona!

PEMBERITAHUAN: Ubah this.activityaktivitas Anda atau tambahkan aktivitas utama dan hapus this.activity;-)

Jika Anda ingin melakukan yang sebaliknya, Anda harus mengubah kode ke lansekap (tapi saya pikir sudah jelas caranya).

Codebeat
sumber
0

Sayangnya, menggunakan metode setRequestedOrientation (...) akan menyebabkan aktivitas dimulai ulang, jadi meskipun Anda menyebut ini dalam metode onCreate, ia akan melalui siklus hidup aktivitas dan kemudian akan membuat kembali aktivitas yang sama dengan orientasi yang diminta. Jadi pada jawaban @Brian Christensen Anda harus mempertimbangkan bahwa kode aktivitas mungkin dipanggil dua kali, ini dapat memiliki efek buruk (tidak hanya visual, tetapi juga pada permintaan jaringan, analitik, dll.).

Selain itu, untuk menetapkan atribut configChanges dalam manifes menurut saya merupakan trade-off besar, yang bisa memakan biaya besar untuk refactoring. Android Devs tidak merekomendasikan untuk mengubah atribut itu .

Akhirnya, mencoba untuk mengatur screenOrientation entah bagaimana berbeda (untuk menghindari masalah restart) tidak mungkin, secara statis tidak mungkin karena manifes statis yang tidak dapat diubah, secara terprogram hanya mungkin untuk memanggil metode itu dalam aktivitas yang sudah dimulai.

Ringkasan: Menurut pendapat saya, saran @Brian Christensen adalah trade-off terbaik, tetapi berhati-hatilah dengan masalah aktivitas memulai kembali.

mathew11
sumber