Android: разрешить портрет и пейзаж для планшетов, но заставить портрет на телефоне? - PullRequest
178 голосов
/ 09 марта 2012

Я бы хотел, чтобы планшеты могли отображаться в портретной и альбомной ориентации (sw600dp или выше), но телефоны должны быть только в портретной ориентации. Я не могу найти способ условно выбрать ориентацию. Есть предложения?

Ответы [ 9 ]

428 голосов
/ 10 февраля 2013

Вот хороший способ использования resources и определителей размера .

Поместите этот bool-ресурс в res / values ​​как bools.xml или как угодно (имена файлов don 'не имеет значения здесь):

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

Поместите это в res / values-sw600dp и res / values-xlarge:

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

См. этот дополнительный ответ дляПомогите добавить эти каталоги и файлы в Android Studio.

Затем в методе onCreate ваших действий вы можете сделать следующее:

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

Устройства с наименьшей шириной более 600 dpнаправление, или x-large на устройствах до Android 3.2 (планшеты, в основном) будет вести себя как обычно, на основе датчика и вращения, заблокированного пользователем, и т. д. .Все остальное (телефоны, в основном) будет только портретным.

28 голосов
/ 09 марта 2012

Вы можете попробовать этот способ сначала получить размер экрана устройства

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

, а затем установить ориентацию в соответствии с этим

setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
9 голосов
/ 26 июля 2012

Вот как я это сделал (вдохновлено http://androidblogger.blogspot.com/2011/08/orientation-for-both-phones-and-tablets.html):

В AndroidManifest.xml для каждого занятия вы хотите иметь возможность переключаться между портретным и ландшафтным (обязательно добавьте screenSize- вам раньше не нужно было это!) Вам не нужно устанавливать ориентацию экрана здесь.:

android:configChanges="keyboardHidden|orientation|screenSize"

Методы, добавляемые в каждое действие:

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

и: (если вы не переопределите этот метод, приложение вызовет onCreate () при изменении ориентации)

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

В onCreate () каждого занятия:

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

Единственное, чего я не могу понять, это как заставить приложение изменять файлы макета при переключении спейзаж в портрет или наоборот.Я предполагаю, что ответ делает нечто похожее на то, что делает приведенная выше ссылка, но я не смог заставить это работать на меня - он удалил все мои данные.Но если у вас достаточно простое приложение с одинаковым файлом макета для портретной и альбомной ориентации, это должно сработать.

7 голосов
/ 03 сентября 2016

Дополнение к принятому ответу

Вы можете выполнить следующие действия в Android Studio, чтобы добавить каталоги res/values-sw600dp и res/values-large с их файлами bools.xml.

значения-sw600dp

Прежде всего, на вкладке Project выберите фильтр Project (а не Android) в навигаторе.

enter image description here

Затем щелкните правой кнопкой мыши каталог app/src/main/res. Выберите Новый > Каталог ресурсов Android .

Выберите Наименьшая ширина экрана , а затем нажмите кнопку >> .

enter image description here

Введите 600 для наименьшей ширины экрана. Имя каталога будет создано автоматически. Скажи ОК.

enter image description here

Затем щелкните правой кнопкой мыши вновь созданный файл values-sw600dp. Выберите Новый > Файл ресурсов значений . Введите bools в качестве имени.

значения, большой

Добавление каталога values-large необходимо только в том случае, если вы поддерживаете предварительно Android 3.2 (уровень API 13). В противном случае вы можете пропустить этот шаг. Каталог values-large соответствует values-sw600dp. (values-xlarge соответствует values-sw720dp.)

Чтобы создать каталог values-large, выполните те же действия, что и выше, но в этом случае выберите Размер вместо Наименьшей ширины экрана. Выберите Большой . Имя каталога будет создано автоматически.

enter image description here

Щелкните правой кнопкой мыши каталог, как и раньше, чтобы создать файл bools.xml.

6 голосов
/ 16 ноября 2016

После ответа Джинни , я думаю, что самый надежный способ сделать это заключается в следующем:

Как описано здесь , поместите логическое значение в ресурсы sw600dp.Он должен иметь префикс sw , иначе он не будет работать должным образом:

в res / values-sw600dp / sizess.xml

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

в res / values ​​/dimensions.xml

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

Затем создайте метод для получения этого логического значения:

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

И базовое действие, расширяемое от действий, для которых необходимо это поведение:

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

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

Таким образом, каждое действие будет расширять BaseActivity:

public class LoginActivity extends BaseActivity //....

Важно : даже если вы расширяете с BaseActivity, вы должны добавить строку android:configChanges="orientation|screenSize" к каждому Activityв вашем AndroidManifest.xml:

    <activity
        android:name=".login.LoginActivity"
        android:configChanges="orientation|screenSize">
    </activity>
4 голосов
/ 20 ноября 2014

Ну, это немного поздно, но вот XML-Only , но решение для взлома, которое не воссоздает действие, как setRequestedOrientation, если нужно изменить ориентацию:

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

0 голосов
/ 01 июля 2019

Другие решения не работали для меня.У меня все еще были странные проблемы с ориентацией на диалоги и вопросы отдыха.Мое решение состояло в том, чтобы расширить действие, сделав его портретом в манифесте.

Пример:

public class MainActivityPhone extends MainActivity {}

manifest.xml:

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

в активности на экране:1009 *

    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 голосов
/ 03 ноября 2017

К сожалению, использование метода setRequestedOrientation (...) приведет к перезапуску действия, поэтому даже если вы вызовете его в методе onCreate, он пройдет жизненный цикл действия и затем заново создастта же активность в запрошенной ориентации.Поэтому при ответе @Brian Christensen вы должны учитывать, что код активности может вызываться дважды, что может иметь плохие последствия (не только визуальные, но и сетевые запросы, аналитика и т. Д.).

Кроме того, для установкиатрибут configChanges в манифесте, по моему мнению, является большим компромиссом, который может потребовать огромных затрат на рефакторинг. Разработчики Android не рекомендуют изменять этот атрибут .

Наконец, попытка установить screenOrientation как-то иначе (чтобы избежать проблемы перезапуска) невозможна, статически невозможна из-за статического манифеста, который можетНе изменяйте, программно можно вызвать этот метод только в уже запущенном действии.

Резюме: На мой взгляд, предложение @Brian Christensen - лучший компромисс, но помните о проблеме возобновления активности.

0 голосов
/ 13 марта 2014

Старый вопрос, который я знаю.Чтобы приложение всегда работало в портретном режиме, даже если ориентация может быть или поменялась местами и т. Д. (Например, на планшетах), я разработал эту функцию, которая используется для установки устройства в правильной ориентации без необходимости знать, как портрет и пейзажфункции организованы на устройстве.

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

    }

Работает как шарм!

ВНИМАНИЕ. Измените this.activity в зависимости от действия или добавьте его к основному виду деятельности и удалите this.activity; -)

.пейзаж (но я думаю понятно как это).

...