Android:允许平板电脑的纵向和横向,但强制手机上的肖像?

Ken*_*and 181 android tablet screen-orientation

我希望平板电脑能够以纵向和横向(sw600dp或更高)显示,但手机仅限于纵向.我找不到有条件选择方向的方法.有什么建议?

小智 436

这是使用资源大小限定符的好方法.

将此bool资源放在res/values中作为bools.xml或其他任何内容(文件名在这里无关紧要):

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <bool name="portrait_only">true</bool>
    </resources>
Run Code Online (Sandbox Code Playgroud)

把这个放在res/values-sw600dp和res/values-xlarge中:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <bool name="portrait_only">false</bool>
    </resources>
Run Code Online (Sandbox Code Playgroud)

有关在Android Studio中添加这些目录和文件的帮助,请参阅此补充答案.

然后,在您的活动的onCreate方法中,您可以这样做:

    if(getResources().getBoolean(R.bool.portrait_only)){
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }
Run Code Online (Sandbox Code Playgroud)

在最小宽度方向上超过600 dp的设备,或在Android 3.2之前的设备(基本上是平板电脑)上的x-large将基于传感器和用户锁定旋转等行为正常.其他一切(电话,几乎)只会是肖像.

  • 好吧,这可能会在横向启动时重新启动活动,请参阅http://developer.android.com/reference/android/app/Activity.html#setRequestedOrientation%28int%29 (6认同)
  • 如果我在横向模式下启动应用程序,它仍会在短时间内显示横向模式. (6认同)
  • @dan 我通过向清单中的每个活动添加 'android:screenOrientation="behind"' 找到了解决此问题的方法。在此处查看我的完整答案:/sf/ask/3005520521/#46565259 (3认同)
  • 我是否也需要使用`xlarge` 或者我可以只使用`sw600dp`?这些天可能没有任何平板电脑运行 &lt; 3.2。 (2认同)

Avi*_*nku 28

您可以尝试这种方式首先获取设备的屏幕尺寸

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();
}
Run Code Online (Sandbox Code Playgroud)

然后根据它设置方向

setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Run Code Online (Sandbox Code Playgroud)

  • 我应该使用setRequestedOrientation()方法的方法是什么?一旦onCreate开始,它已经选择了它想要的方向. (4认同)

Gin*_*nny 9

我是这样做的(灵感来自http://androidblogger.blogspot.com/2011/08/orientation-for-both-phones-and-tablets.html):

在AndroidManifest.xml中,对于您希望能够在纵向和横向之间切换的每个活动(确保添加screenSize - 您以前不需要这样做!)您无需在此处设置屏幕方向.:

android:configChanges="keyboardHidden|orientation|screenSize"
Run Code Online (Sandbox Code Playgroud)

在每个Activity中添加的方法:

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

和:(如果你没有覆盖这个方法,应用程序将在更改方向时调用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
}
Run Code Online (Sandbox Code Playgroud)

在每个Activity的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 
}
Run Code Online (Sandbox Code Playgroud)

我唯一无法弄清楚的是如何在从横向切换到纵向时将应用程序更改为布局文件,反之亦然.我假设答案是做与上述链接类似的事情,但我无法让它为我工作 - 它删除了我的所有数据.但是,如果你有一个足够简单的应用程序,你有相同的纵向和横向布局文件,这应该工作.

  • 将横向布局放在layout-land文件夹中 (2认同)

Sur*_*gch 9

补充接受的答案

您可以在Android Studio中执行以下步骤,以使用其文件添加res/values-sw600dpres/values-large目录bools.xml.

价值观sw600dp

首先,从Project选项卡中选择导航器中的Project(而不是Android)过滤器.

在此输入图像描述

然后右键单击该app/src/main/res目录.选择新建 > Android资源目录.

选择最小屏幕宽度,然后按>>按钮.

在此输入图像描述

键入600最小屏幕宽度.将自动生成目录名称.说OK.

在此输入图像描述

然后右键单击新创建的values-sw600dp文件.选择新建 > 值资源文件.键入bools的名字.

值,大

values-large只有在支持Android 3.2(API级别13)之前,才需要添加目录.否则,您可以跳过此步骤.该values-large目录对应于values-sw600dp.(values-xlarge对应于values-sw720dp.)

要创建values-large目录,请按照上述步骤操作,但在这种情况下,请选择" 大小"而不是"最小屏幕宽度".选择.将自动生成目录名称.

在此输入图像描述

像以前一样右键单击该目录以创建该bools.xml文件.


Mic*_*cer 8

我对提供的解决方案有疑问,最后这对我有用:

  1. AndroidManifest.xmlActivity 的方向设置为“锁定”:
<activity
    android:name="com.whatever.YourActivity"
    android:screenOrientation="locked"
    ... />
Run Code Online (Sandbox Code Playgroud)
  1. OnCreate(...)您的 Activity 的方法中,使用以下内容:
@SuppressLint("SourceLockedOrientationActivity")
override fun onCreate(savedInstanceState: Bundle?) {
    if (isTablet(resources)) {
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
    } else if (resources.configuration.orientation != Configuration.ORIENTATION_PORTRAIT) {
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
    }
    super.onCreate(savedInstanceState)
}
Run Code Online (Sandbox Code Playgroud)

请注意,您不需要使用带有资源中布尔值的黑客解决方案,您可以使用类isTablet(resources)中的方法DeviceProperties,除了其他检查 if 之外smallestScreenWidthDp >= 600


Rom*_*naV 6

按照Ginny的回答,我认为最可靠的方法如下:

如上所述这里,投入资源sw600dp一个布尔值.它必须有前缀sw,否则它将无法正常工作:

在res/values-sw600dp/dimens.xml中

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isTablet">true</bool>
</resources>
Run Code Online (Sandbox Code Playgroud)

在res/values/dimens.xml中

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isTablet">false</bool>
</resources>
Run Code Online (Sandbox Code Playgroud)

然后创建一个方法来检索该布尔值:

public class ViewUtils {
    public static boolean isTablet(Context context){
        return context.getResources().getBoolean(R.bool.isTablet);
    }
}
Run Code Online (Sandbox Code Playgroud)

以及从您希望此行为的活动扩展的基本活动:

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

        if (!ViewUtils.isTablet(this)) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以每个活动都会扩展BaseActivity:

public class LoginActivity extends BaseActivity //....
Run Code Online (Sandbox Code Playgroud)

重要提示:即使您从中扩展BaseActivity,也必须在AndroidManifest.xml中android:configChanges="orientation|screenSize"为每个添加行Activity:

    <activity
        android:name=".login.LoginActivity"
        android:configChanges="orientation|screenSize">
    </activity>
Run Code Online (Sandbox Code Playgroud)


gun*_*ess 5

好吧,这有点晚了,但是,这是一个仅 XML的 hack 解决方案,它不会像setRequestedOrientation必须改变方向那样重新创建活动:

/sf/answers/1891111561/


Stu*_*ell 5

我最近遇到了这个要求,但不想使用任何这些解决方案。它们都有一个共同点,那就是它们都setRequestedOrientation以编程方式调用。这样做的问题是它设置方向太晚并导致轻微的 UI 故障。如果您的设备在启动应用程序时处于横向状态,则它会横向加载然后旋转。如果您使用主题创建闪屏效果,这一点尤其明显,因为您会看到背景图像的方向错误。这也会对您的应用程序在最近的应用程序中的显示方式以及配置更改问题产生副作用,如其他答案评论中所述。

结论需要在清单中设置正确的方向,以便系统无需启动应用程序即可知道方向。

这是关于如何执行此操作的解决方案(这需要相当多的努力,但你会睡得更好)

首先将清单中的方向设置为占位符

<activity
      android:screenOrientation="${screenOrientation}"
     ...
</activity>
Run Code Online (Sandbox Code Playgroud)

然后,我们需要添加普通/平板电脑风格来设置 app/build.gradle 中的值。(如果您已经使用风味,则可以通过新的构建类型来实现)

android {
    ...
    productFlavors {
        normal {
            manifestPlaceholders = [screenOrientation: "portrait"]
        }
        tablet {
            manifestPlaceholders = [screenOrientation: "unspecified"]
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们需要告诉平板电脑构建它仅适用于大型设备。这可以通过添加仅平板电脑清单与默认清单合并来完成。添加新的清单文件位于->

app
 src
  tablet
   AndroidManifest.xml
Run Code Online (Sandbox Code Playgroud)

以下是所有清单需求,因为它与默认清单合并 ->

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="{package}">

    <supports-screens
        android:smallScreens="false"
        android:normalScreens="false"
        android:largeScreens="true"
        android:xlargeScreens="true"
        android:requiresSmallestWidthDp="600"
        />

</manifest>
Run Code Online (Sandbox Code Playgroud)

最后一个技巧是我们需要通过版本代码来区分构建,因为 Playstore 不能有两个具有匹配代码的上传。我们希望确保平板电脑(限制性更强的版本)具有更高的代码。一个简单的方法是获取基本代码,然后用于平板电脑base * 2和普通base * 2 - 1. 我使用 CI 来实现此目的,基本代码是内部版本号,但很容易按照您的风格进行硬编码。

现在构建两种口味来创建

 app-normal.apk/aab (v1.0.0, version code 1)
 app-tablet.apk/aab (v1.0.0, version code 2)
Run Code Online (Sandbox Code Playgroud)

将它们作为多个 apk/aab 上传到 Playstore,然后,如果在平板电脑上下载,Playstore 会为它们提供旋转的 apk,如果在手机上下载,则仅提供一个肖像。

注意:仅在通过 Google Playstore/Amazon Kindle 分发时有效

进一步阅读https://developer.android.com/google/play/publishing/multiple-apks https://developer.amazon.com/docs/fire-tablets/ft-screen-layout-and-resolution.html