Я хотел бы, чтобы планшеты могли отображаться в портретном и ландшафтном (sw600dp или выше), но телефоны ограничивались только портретами. Я не могу найти способ условно выбрать ориентацию. Любые предложения?
Android: разрешить портрет и пейзаж для планшетов, но заставить портрет на телефоне?
Ответ 1
Здесь хороший способ использования resources и отборочные отборочные числа.
Поместите этот ресурс bool в res/values как bools.xml или что-то еще (имена файлов здесь неважны):
<?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 дП в наименьшем направлении ширины или x-large на устройствах pre-Android 3.2 (планшеты в основном) будут вести себя как обычно, на основе датчика и вращением пользователя и т.д.. Все остальное (телефоны, в значительной степени) будет только портретом.
Ответ 2
Вы можете попробовать таким образом, сначала получить размер экрана устройства
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);
Ответ 3
Вот как я это сделал (вдохновленный 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
}
Единственное, что я не могу понять, так это то, как заставить приложение изменять файлы макета при переключении с ландшафта на портрет или наоборот. Я предполагаю, что ответ делает что-то похожее на то, что делает ссылка выше, но я не мог заставить это работать для меня - он удалил все мои данные. Но если у вас достаточно простое приложение, у вас есть тот же файл макета для портрета и пейзажа, это должно сработать.
Ответ 4
Дополнение к принятому ответу
Вы можете сделать следующие шаги в Android Studio, чтобы добавить каталоги res/values-sw600dp
и res/values-large
со своими файлами bools.xml
.
значения-sw600dp
Прежде всего, на вкладке "Проект" выберите в навигаторе фильтр "Проект (а не Android)".
Затем щелкните правой кнопкой мыши каталог app/src/main/res
. Выберите Новый > Каталог ресурсов Android.
Выберите Наименьшая ширина экрана, а затем нажмите кнопку → .
Введите 600
для наименьшей ширины экрана. Имя каталога будет автоматически сгенерировано. Скажите "ОК".
Затем щелкните правой кнопкой мыши на вновь созданный файл values-sw600dp
. Выберите Новый > Файл ресурсов значений. Введите bools
для имени.
значения, большие
Добавление каталога values-large
необходимо только в том случае, если вы поддерживаете предварительный Android 3.2 (уровень API 13). В противном случае вы можете пропустить этот шаг. Каталог values-large
соответствует values-sw600dp
. (values-xlarge
соответствует values-sw720dp
.)
Чтобы создать каталог values-large
, выполните те же действия, что и выше, но в этом случае выберите Размер, а не Наименьшая ширина экрана. Выберите Большой. Имя каталога будет автоматически сгенерировано.
Щелкните правой кнопкой мыши каталог по-прежнему, чтобы создать файл bools.xml
.
Ответ 5
После Джинни ответьте, я думаю, что самый надежный способ сделать это:
Как описано здесь, поставьте логическое значение в ресурсах sw600dp. Он должен иметь префикс sw, иначе он не будет работать должным образом:
в res/values-sw600dp/dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="isTablet">true</bool>
</resources>
в res/values /dimens.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>
Ответ 6
Ну, это немного поздно, но вот XML-Only, но хакерское решение, которое не воссоздает активность как setRequestedOrientation
, если нужно изменить ориентацию:
Ответ 7
Старый вопрос, который я знаю. Чтобы запускать приложение всегда в портретном режиме, даже если ориентация может быть или обменивается и т.д. (Например, на планшетах), я разработал эту функцию, которая используется для установки устройства в правильной ориентации без необходимости знать, как портрет и пейзаж функции организованы на устройстве.
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 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
; -)
Если вы хотите сделать обратное, вы должны изменить код на пейзаж (но я думаю, что это понятно, как это сделать).
Ответ 8
К сожалению, использование метода setRequestedOrientation (...) приведет к перезапуску активности, поэтому даже если вы вызываете это в onCreate метод будет проходить жизненный цикл активности, а затем он будет воссоздавать ту же активность в запрошенной ориентации. Поэтому в ответ @Brian Christensen вы должны подумать, что код активности может быть вызван дважды, это может иметь плохие последствия (не только визуальные, но и сетевые запросы, аналитика и т.д.).
Кроме того, для установки атрибута configChanges в манифесте, на мой взгляд, большой компромисс, который может потребовать значительных затрат на рефакторинг. Android Devs не рекомендует изменять этот атрибут.
Наконец, попытка установить ScreenOrientation каким-то другим (во избежание проблемы с перезапуском) невозможна, статически невозможна из-за статического манифеста, который не может быть изменен, программным способом можно только вызвать этот метод в уже запущенной деятельности,
Резюме. На мой взгляд, предложение @Brian Christensen является лучшим компромиссом, но следует помнить о проблеме перезапуска.
Ответ 9
Другие решения не спомогли мне. У меня все еще были странные проблемы с ориентацией на диалоги и вопросы отдыха. Мое решение состояло в том, чтобы расширить Activity, превратив ее в декларацию.
Пример:
public class MainActivityPhone extends MainActivity {}
manifest.xml:
<activity
android:screenOrientation="landscape"
android:name=".MainActivityPhone"
android:theme="@style/AppTheme.NoActionBar" />
в заставке деятельности:
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);