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

时间:2012-03-09 01:34:17

标签: android tablet screen-orientation

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

12 个答案:

答案 0 :(得分:426)

这是使用resourcessize qualifiers的好方法。

将此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中添加这些目录和文件的帮助,请参阅this supplemental answer

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

    if(getResources().getBoolean(R.bool.portrait_only)){
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }

在最小宽度方向上超过600 dp的设备,或在Android 3.2之前的设备(平板电脑,基本上)上的x-large将表现得正常,based on sensor and user-locked rotation, etc。其他一切(手机,几乎都只)只是肖像。

答案 1 :(得分: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();
}

然后根据

设置方向
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

答案 2 :(得分:8)

我是这样做的(灵感来自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 
}

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

答案 3 :(得分:7)

accepted answer

的补充

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

值-sw600dp

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

enter image description here

然后右键单击app/src/main/res目录。选择&gt; Android资源目录

选择最小屏幕宽度,然后按&gt;&gt; 按钮。

enter image description here

输入600作为最小屏幕宽度。将自动生成目录名称。说好。

enter image description here

然后右键单击新创建的values-sw600dp文件。选择&gt; 值资源文件。输入bools作为名称。

值-大

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

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

enter image description here

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

答案 4 :(得分:6)

关注Ginny's answer,我认为最可行的方法如下:

如上所述here,在资源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"添加到AndroidManifest.xml中的每个Activity

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

答案 5 :(得分:4)

嗯,这有点晚了,但是,这是仅限XML ,但是如果必须更改方向,则不会重新创建setRequestedOrientation活动的黑客解决方案:< / p>

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

答案 6 :(得分:2)

接受回答之后,我添加了带有解决方案的kotlin文件,希望它可以对某人有所帮助

将此布尔资源放在res/values中,作为 bools.xml 或其他名称(此处文件名无关紧要):

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

将其放在res/values-sw600dpres/values-sw600dp-land中:

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

然后,将其添加到活动或片段中的以下行中

class MyActivity : Activity() {

    @SuppressLint("SourceLockedOrientationActivity")
    override fun onCreate(savedInstanceState: Bundle?) {
        if (resources.getBoolean(R.bool.portrait_only)) {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        }
        super.onCreate(savedInstanceState)
    }

    @SuppressLint("SourceLockedOrientationActivity")
    override fun onConfigurationChanged(newConfig: Configuration) {
        if (resources.getBoolean(R.bool.portrait_only)) {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        }
        super.onConfigurationChanged(newConfig)
    }
}

答案 7 :(得分:1)

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

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

这是解决方法(虽然需要很多努力,但是您会睡得更好)

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

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

然后,我们需要添加普通/平板电脑口味以在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不能上传两个带有匹配代码的文件。我们要确保平板电脑(限制更严格的版本)具有更高的代码。一种简单的方法是获取基本代码,然后输入平板电脑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)

将它们以多次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

答案 8 :(得分:0)

老问题我知道。为了始终以纵向模式运行您的应用程序,即使可能或已交换方向等(例如在平板电脑上)我设计了此功能,用于将设备设置在正确的方向,而无需了解纵向和横向功能在设备上组织。

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

如果你想做相反的事情,你必须将代码更改为横向(但我认为很清楚如何)。

答案 9 :(得分:0)

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

此外,在我看来,在清单中设置configChanges属性是一个很大的权衡,这可能需要大量的重构成本。 Android Devs are not recommending to change that attribute

最后,尝试将screenOrientation设置为某种程度上不同(以避免重启问题)是不可能的,由于无法更改的静态清单,静态不可能,以编程方式只能在已启动的活动中调用该方法。

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

答案 10 :(得分:0)

其他解决方案对我不起作用。我仍然在对话和娱乐方面有一些奇怪的方向性问题。我的解决方案是扩展活动,将其强制为清单中的肖像。

示例:

public class MainActivityPhone extends MainActivity {}

manifest.xml:

        <activity
        android:screenOrientation="portrait"
        android:name=".MainActivityPhone"
        android:theme="@style/AppTheme.NoActionBar" />

splashcreen活动中的

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

答案 11 :(得分:0)

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

android:screenOrientation="fullSensor"

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