Android: tabletler için portre ve manzaraya izin verin, ancak telefonu telefonda zorla?


191

Tabletlerin dikey ve yatay (sw600dp veya üstü) görüntüde görüntülenmesini istiyorum, ancak telefonların yalnızca portre ile sınırlı olması gerekir. Koşullu olarak bir yönlendirme seçmenin bir yolunu bulamıyorum. Baska öneri?


Bunun bir yolu, klasör layout-landiçinde olduğu gibi telefonlar için peyzaj düzenleri tasarlamak DEĞİLDİR res.
Hayalet

12
Bu sadece portre düzeninin yatay olarak görünmesine neden olur. Aslında bir telefonun manzaraya dönmesini engellemez.
radley

Yanıtlar:


446

Kaynakları ve boyut niteleyicileri kullanmanın iyi bir yolu .

Bu bool kaynağını res / değerleri içine bools.xml veya başka bir şekilde yerleştirin (dosya adları burada önemli değildir):

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

Bunu res / değerleri-sw600dp ve res / değerleri-xlarge içine koyun:

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

Android Studio'da bu dizinleri ve dosyaları ekleme konusunda yardım için bu ek cevaba bakın .

Ardından, Etkinliklerinizin onCreate yönteminde şunları yapabilirsiniz:

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

En küçük genişlik yönünde 600 dp'den fazla veya Android 3.2 öncesi cihazlarda (temel olarak tabletler) x-büyük olan cihazlar , sensör ve kullanıcı kilitli dönüşe vb . Dayalı olarak normal gibi davranacaktır . Diğer her şey (telefonlar, hemen hemen) sadece portre olacaktır.


1
Ben de kullanmam gerekiyor mu xlargeyoksa sadece kullanabilir sw600dpmiyim? Muhtemelen bu günlerde <3,2 çalışan herhangi bir tablet yoktur.
theblang

7
Bu, manzaraya başladığında etkinliği potansiyel olarak yeniden başlatır, bkz. Developer.android.com/reference/android/app/…
Bondax

1
@Bondax Bu yorum yalnızca "Etkinlik şu anda ön plandaysa veya ekran yönünü başka bir şekilde etkiliyorsa" geçerlidir, bu durumda onCreate'da olduğumuzdan bu durumda olamaz.
Brian Christensen

1
@BrianChristensen İstenen yönelimi ayarlarken bir etkinliği yeniden başlattığımı gözlemledim onCreate(). Çağrıyı setRequestedOrientation()zaman ve bağlamda farklı bir konuma taşıdığımda, yeniden başlatma artık gerçekleşmedi.
Bondax

8
uygulamayı yatay modda başlatırsam, yine de kısa bir süre için yatay mod gösterir.
目 白 目

29

Önce cihazın ekran boyutunu elde etmek için bu şekilde deneyebilirsiniz

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

ve ardından yönlendirmeyi buna göre ayarlayın

setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

4
SetRequestedOrientation () yöntemini hangi yöntemi kullanmalıyım? OnCreate başladıktan sonra, hangi yönü istediğini zaten seçmiştir.
Kenny Wyland

kenny bunu kontrol sana yardımcı olabilir düşünüyorum stackoverflow.com/questions/2833474/…
Avi Kumar Manku

Bu cevabın kaldırıldığını görüyorum, ancak sorunun çözüldüğünden emin değilim. Configurationsağlar screenLayoutbilgiler - DPI. Oysa soru fiziksel cihaz ekran boyutu - telefon VS tablet ile ilgilidir. Yani, bir olabilir Configuration.SCREENLAYOUT_SIZE_NORMALve bir MDPI tablet olurdu.
gece


10

EKİ kabul cevap

Dosyalarını res/values-sw600dpve res/values-largedizinlerini eklemek için Android Studio'da aşağıdaki adımları uygulayabilirsiniz bools.xml.

değerler sw600dp

Her şeyden önce, Proje sekmesinden gezgindeki Proje (Android yerine) filtresini seçin.

resim açıklamasını buraya girin

Ardından app/src/main/resdizini sağ tıklayın . Yeni > Android Kaynak Dizini'ni seçin .

En Küçük Ekran Genişliği'ni seçin ve ardından >> düğmesine basın .

resim açıklamasını buraya girin

Yazın 600en küçük ekran genişliği için. Dizin adı otomatik olarak oluşturulur. Tamam de.

resim açıklamasını buraya girin

Ardından yeni oluşturulan values-sw600dpdosyayı sağ tıklayın . Yeni > Değerler kaynak dosyası'nı seçin . Tip boolsadı için.

değerleri geniş

Bir values-largedizin eklemek yalnızca Android 3.2 öncesi (API seviye 13) destekliyorsanız gereklidir. Aksi takdirde bu adımı atlayabilirsiniz. values-largeDizin tekabül values-sw600dp. ( values-xlargekarşılık gelir values-sw720dp.)

values-largeDizini oluşturmak için yukarıdakiyle aynı adımları izleyin, ancak bu durumda En Küçük Ekran Genişliği yerine Boyut'u seçin . Seç Büyük . Dizin adı otomatik olarak oluşturulur.

resim açıklamasını buraya girin

bools.xmlDosyayı oluşturmak için önceki gibi sağ tıklayın .


2
Bu işe yaramazsa bana bildirin, ben hallederim. Benim için çalıştı. Bir downvote var ama yorum yok bu yüzden ne düzeltmek bilmiyorum.
16'da Suragch

9

İşte nasıl yaptım ( http://androidblogger.blogspot.com/2011/08/orientation-for-both-phones-and-tablets.html'den esinlenerek ):

AndroidManifest.xml dosyasında, portre ve manzara arasında değiştirmek istediğiniz her etkinlik için (screenSize eklediğinizden emin olun - buna ihtiyacınız yoktu!) Burada bir ekran yönü ayarlamanıza gerek yoktur. :

android:configChanges="keyboardHidden|orientation|screenSize"

Her Faaliyete eklenecek yöntemler:

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

ve: (bu yöntemi geçersiz kılmazsanız, uygulama yön değiştirirken onCreate () yöntemini çağırır)

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

Her bir Etkinliğin onCreate () öğesinde:

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

Anlayamadığım tek şey, uygulamanın yataydan portreye veya tersi yönde geçiş yaparken düzen dosyalarını değiştirmesini sağlamaktır. Cevabın yukarıdaki bağlantıya benzer bir şey yaptığını varsayıyorum, ancak bunu benim için çalıştıramadım - tüm verilerimi sildi. Ancak, portre ve manzara için aynı düzen dosyasına sahip olduğunuz kadar basit bir uygulamanız varsa, bu işe yaramalıdır.


2
peyzaj düzenlerini düzen-arazi klasörünüze koyun
radley

Süper onConfigurationChanged çağrmazsanız bir istisna alacaksınız
RominaV

8

Ginny'nin cevabını takiben , bunu yapmanın en güvenilir yolunun şöyle olduğunu düşünüyorum:

Açıklandığı gibi burada , kaynaklar sw600dp bir boole koydu. Önek sw olmalıdır, aksi takdirde düzgün çalışmaz:

res / değerleri-sw600dp / dimens.xml

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

res / değerleri / dimens.xml içinde

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

Ardından, bu boole'yi almak için bir yöntem yapın:

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

Ve bu davranışı istediğiniz etkinliklerden genişleyecek temel etkinlik:

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

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

Böylece her etkinlik BaseActivity'yi genişletir:

public class LoginActivity extends BaseActivity //....

Önemli : Genişletseniz bile , AndroidManifest.xml dosyasında her birine BaseActivitysatır eklemeniz gerekir :android:configChanges="orientation|screenSize"Activity

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

5

Peki, bu biraz geç ama burada sadece XML ama setRequestedOrientationoryantasyonu değiştirmek zorundaymış gibi bir aktiviteyi yeniden yaratmayan bir hack çözümü :

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


1
Çalışmaz, tabletler her zaman telefonların yönünü alır. Görünüşe göre android: screenOrientation, herhangi bir kaynak değiştirici uygulanmadan önce manifest'teki tüm etkinlikler için tam olarak bir kez ayarlanır.
0101100101

2

Kabul edilen cevabı takiben , kotlin dosyasını birisine yardımcı olacağını umarak çözüm ekliyorum

Bu bool kaynağı koyun res/valuesolarak bools.xml (dosya isimleri burada olsun yok) ya da her neyse:

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

Bunu içine koyun res/values-sw600dpve res/values-sw600dp-land:

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

Ardından, etkinliğinizdeki veya fragmanvitedeki aşağıdaki satırlara ekleyin

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

1

Diğer çözümler benim için işe yaramadı. Diyaloglar ve rekreasyon konularında hala garip bir yönelim problemim vardı. Benim çözümüm Faaliyet'i uzatmak ve onu tezahür içinde portre olarak zorlamaktı.

Misal:

public class MainActivityPhone extends MainActivity {}

Manifest.xml:

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

splashcreen etkinliğinde:

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

0

Eski bir soru biliyorum. Yönünüzü değiştirebilse veya takas etse bile uygulamanızı her zaman portre modunda çalıştırmak için (örneğin tabletlerde) Dikey ve yatay konumun nasıl olduğunu bilmenize gerek kalmadan cihazı doğru yönde ayarlamak için kullanılan bu işlevi tasarladım. özellikler cihazda düzenlenmiştir.

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

    }

Tıkır tıkır çalışıyor!

DİKKAT: this.activityEtkinliğinize göre değiştirin veya ana etkinliğe ekleyin ve this.activity;-) kaldırın

Eğer tersini yapmak istiyorsanız, kodu manzaraya değiştirmeniz gerekir (ama bunun nasıl açık olduğunu düşünüyorum).


0

Ne yazık ki, setRequestedOrientation (...) yönteminin kullanılması etkinliğin yeniden başlatılmasına neden olur, bu yüzden bunu onCreate yönteminde çağırsanız bile etkinlik yaşam döngüsü boyunca ilerler ve ardından aynı etkinliği istenen yönde yeniden oluşturur. Yani @Brian Christensen'ın cevabında, etkinlik kodunun iki kez çağrılabileceğini düşünmelisiniz, bunun kötü etkileri olabilir (sadece görsel değil, aynı zamanda ağ isteklerinde, analitiklerde vb.).

Ayrıca, manifChanges özniteliğini manifest'te ayarlamak, bence büyük bir yeniden dengeleme maliyetidir ve bu da büyük bir yeniden düzenleme maliyeti alabilir. Android Devs, bu özelliği değiştirmenizi önermez .

Son olarak, screenOrientation'u bir şekilde farklı ayarlamaya çalışmak (yeniden başlatma probleminden kaçınmak için) imkansızdır, değiştirilemeyen statik tezahür nedeniyle statik olarak imkansızdır, programlı olarak sadece bu yöntemi zaten başlatılmış aktivitede çağırmak mümkündür.

Özet: Bence, @Brian Christensen önerisi en iyi değiş tokuş, ancak yeniden başlatılan aktivite sorununun farkında olun.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.