我希望平板电脑能够显示肖像和景观(sw600dp或更大),但手机仅限于肖像。我找不到任何有条件地选择方向的方法。有什么建议吗?


当前回答

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

如本文所述,在资源sw600dp中放入一个布尔值。它必须有前缀sw,否则它将无法正常工作:

在res / values-sw600dp / dimens.xml

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

在res /价值/ 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);
    }
}

和一个base activity来扩展你想要的行为:

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"到每个活动在你的AndroidManifest.xml:

    <activity
        android:name=".login.LoginActivity"
        android:configChanges="orientation|screenSize">
    </activity>

其他回答

其他的解决方案对我都不起作用。在对话和娱乐方面,我仍然有一些奇怪的方向问题。我的解决方案是扩展活动,迫使它作为肖像在manifest。

例子:

public class MainActivityPhone extends MainActivity {}

manifest.xml:

        <activity
        android:screenOrientation="portrait"
        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);

I recently came across this requirement but didn't want to use any of these solutions. All of them have in common that they call setRequestedOrientation programmatically. The problem with this is it sets the orientation too late and causes slight UI glitches. If your device is in landscape when you launch the app it loads in landscape then rotates. This is particularly noticeable if you use a theme to create a splash screen effect as you will see the background image in the wrong orientation. This can also have a side effect on how your app is shown in the recent apps and issues with configuration change as noted in other answers comments.

需要在清单中设置正确的方向,这样系统就可以在不启动应用程序的情况下知道方向。

这里有一个解决方案(这是一个相当大的努力,但你会睡得更好)

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

<activity
      android:screenOrientation="${screenOrientation}"
     ...
</activity>

然后我们需要添加一个normal/tablet flavor来设置app/build.gradle中的值。(如果你已经在使用味道,可以用新的构建类型来实现)

android {
    ...
    productFlavors {
        normal {
            manifestPlaceholders = [screenOrientation: "portrait"]
        }
        tablet {
            manifestPlaceholders = [screenOrientation: "unspecified"]
        }
    }
}

现在我们需要告诉平板电脑版本,它只适用于大型设备。这可以通过添加只使用平板电脑的清单来与默认清单合并来实现。在->添加一个新的清单文件

app
 src
  tablet
   AndroidManifest.xml

下面是这个清单所需的全部内容,因为它与默认的清单合并为->

<?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>

最后一个技巧是我们需要通过版本代码来区分构建,因为Playstore不能有两次带有匹配代码的上传。我们希望确保平板电脑(更严格的构建)具有更高的代码。一个简单的方法是取一个基本代码,然后平板电脑的基本* 2和普通的基本* 2 - 1。我使用CI与基本代码构建数字,但很容易在你的口味硬编码。

现在制作两种口味

 app-normal.apk/aab (v1.0.0, version code 1)
 app-tablet.apk/aab (v1.0.0, version code 2)

将它们以多个apk/aab的形式上传到Playstore,然后如果在平板电脑上下载,Playstore会提供旋转的apk,如果在手机上下载,则只提供一个纵向的apk。

注:仅适用于通过谷歌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

不幸的是,使用setRequestedOrientation(…)方法会导致活动重新启动,所以即使你在onCreate方法中调用这个,它也会经历活动生命周期,然后它会在请求的方向上重新创建相同的活动。所以在@Brian Christensen的回答中,你应该考虑到活动代码可能会被调用两次,这可能会产生不良影响(不仅是视觉上,而且在网络请求、分析等方面也会产生不良影响)。

此外,在清单中设置configChanges属性在我看来是一个很大的权衡,这可能会花费大量的重构成本。Android开发者不建议改变这个属性。

最后,尝试以不同的方式设置screenOrientation(以避免重新启动问题)是不可能的,静态不可能,因为静态manifest不能被改变,编程上只可能在已经启动的活动中调用该方法。

总结:在我看来,@Brian Christensen的建议是最好的权衡,但要注意重新启动活动的问题。

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

如本文所述,在资源sw600dp中放入一个布尔值。它必须有前缀sw,否则它将无法正常工作:

在res / values-sw600dp / dimens.xml

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

在res /价值/ 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);
    }
}

和一个base activity来扩展你想要的行为:

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"到每个活动在你的AndroidManifest.xml:

    <activity
        android:name=".login.LoginActivity"
        android:configChanges="orientation|screenSize">
    </activity>

在清单文件中添加以下代码:

android:screenOrientation="fullSensor"

在layout-land文件夹下创建XML文件