it-swarm.com.ru

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

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

177
Kenny Wyland

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

Поместите этот ресурс 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 dp в направлении наименьшей ширины или x-large на устройствах до Android 3.2 (планшеты, в основном), будут вести себя как обычно, на основе вращения датчика и блокировки пользователя и т.д. . Все остальное (телефоны, в значительной степени) будет только портретным.

417
Brian Christensen

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

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);
28
Avi Kumar Manku

Вот как я это сделал (вдохновленный 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 
}

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

8
Ginny

Дополнение к принятый ответ

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

значения-sw600dp

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

 enter image description here

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

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

 enter image description here

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

 enter image description here

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

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

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

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

 enter image description here

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

7
Suragch

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

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

в res/values-sw600dp/dimensions.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>
6
RominaV

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

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

4
guness

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

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

Если вы хотите сделать наоборот, вы должны изменить код на ландшафт (но я думаю, что это понятно).

0
Codebeat

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

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

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

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

0
mathew11