Android: разрешить портрет и пейзаж для планшетов, но заставить портрет на телефоне?

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

Ответ 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, если нужно изменить ориентацию:

fooobar.com/questions/39581/...

Ответ 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);