Android:允许在平板电脑上使用肖像和风景,但在手机上强制使用肖像?

Android:允许在平板电脑上使用肖像和风景,但在手机上强制使用肖像?,android,tablet,screen-orientation,Android,Tablet,Screen Orientation,我希望平板电脑能够显示纵向和横向(sw600dp或更高),但手机只能显示纵向。我找不到任何有条件地选择方向的方法。有什么建议吗?您可以尝试这种方法,首先获取设备的屏幕大小 if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) { Toast.make

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

您可以尝试这种方法,首先获取设备的屏幕大小

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);
以下是我是如何做到这一点的(灵感来自于):

在AndroidManifest.xml中,对于您希望能够在纵向和横向之间更改的每个活动(请确保添加屏幕大小-您以前不需要它!),您不需要在此处设置屏幕方向:

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

在每个活动的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 
}
我唯一不知道的是,当从横向切换到纵向时,如何让应用程序更改布局文件,反之亦然。我假设答案与上面的链接类似,但我无法让它对我起作用——它删除了我所有的数据。但是如果你有一个足够简单的应用程序,你有相同的纵向和横向布局文件,这应该是可行的。

这里有一个使用和的好方法

将此bool资源以res/values格式作为bools.xml或其他格式(此处文件名无关紧要):


在最小宽度方向上超过600 dp的设备,或者在安卓3.2之前的设备(基本上是平板电脑)上x-large的设备,其性能将与普通设备一样。其他的一切(电话,差不多)都是肖像。

我知道的老问题。为了让你的应用程序始终在纵向模式下运行,即使方向可能会改变或被改变等(例如在平板电脑上),我设计了此功能,用于将设备设置为正确的方向,而无需知道设备上纵向和横向功能是如何组织的

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

    }
工作起来很有魅力

注意: 按您的活动更改
此.activity
,或将其添加到主活动并删除
此.activity
;-)


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

好吧,这有点晚了,但是,这里有一个仅XML,但是如果必须更改方向,一个黑客解决方案不会像
setRequestedOrientation
那样重新创建活动:

对《公约》的补充 您可以在Android Studio中执行以下步骤,添加
res/values-sw600dp
res/values-large
目录及其
bools.xml
文件

值-sw600dp 首先,从项目选项卡中选择导航器中的项目(而不是Android)过滤器

然后右键单击
app/src/main/res
目录。选择新的Android资源目录

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

键入
600
以获得最小屏幕宽度。将自动生成目录名。说“好”

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

价值大 只有在支持Android 3.2之前版本(API级别13)的情况下,才需要添加一个
values large
目录。否则,您可以跳过此步骤。
values large
目录对应于
values-sw600dp
。(
values xlarge
对应于
values-sw720dp

要创建
values large
目录,请执行与上述相同的步骤,但在本例中选择Size而不是最小屏幕宽度。选择Large。将自动生成目录名

如前所述,右键单击目录以创建
bools.xml
文件。

以下是最可靠的方法:

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

在res/values-sw600dp/dimens.xml中

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isTablet">true</bool>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isTablet">false</bool>
</resources>
以及从您希望此行为的活动扩展而来的基本活动:

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 static boolean isXLargeScreen(Context context) {
    return (context.getResources().getConfiguration().screenLayout
    & Configuration.SCREENLAYOUT_SIZE_MASK)
    >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
} 
public class LoginActivity extends BaseActivity //....
重要:即使您从
BaseActivity
扩展,也必须将行
android:configChanges=“orientation | screenSize”
添加到AndroidManifest.xml中的每个
活动中:

    <activity
        android:name=".login.LoginActivity"
        android:configChanges="orientation|screenSize">
    </activity>
        <activity
        android:screenOrientation="portrait"
        android:name=".MainActivityPhone"
        android:theme="@style/AppTheme.NoActionBar" />

不幸的是,使用该方法将导致活动重新启动,因此即使您在onCreate方法中调用该方法,它也将经历活动生命周期,然后它将以请求的方向重新创建相同的活动。因此,在@ Brian Christensen的回答中,您应该考虑活动代码可能被调用两次,这可能会产生不良影响(不仅是视觉上的,而且还包括网络请求、分析等)。 此外,在我看来,在清单中设置configChanges属性是一个巨大的折衷,这可能需要巨大的重构成本

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


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

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

例如:

public class MainActivityPhone extends MainActivity {}
manifest.xml:

    <activity
        android:name=".login.LoginActivity"
        android:configChanges="orientation|screenSize">
    </activity>
        <activity
        android:screenOrientation="portrait"
        android:name=".MainActivityPhone"
        android:theme="@style/AppTheme.NoActionBar" />

接受回答之后,我添加了带有t的kotlin文件
public class MainActivityPhone extends MainActivity {}
        <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);
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="portrait_only">true</bool>
</resources>
<?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)
    }
}
<activity
      android:screenOrientation="${screenOrientation}"
     ...
</activity>
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>
 app-normal.apk/aab (v1.0.0, version code 1)
 app-tablet.apk/aab (v1.0.0, version code 2)
android:screenOrientation="fullSensor"