我希望平板电脑能够以纵向和横向(sw600dp或更大)的方式显示,但手机仅限于纵向。我找不到任何有条件地选择方向的方法。有什么建议吗?
我希望平板电脑能够以纵向和横向(sw600dp或更大)的方式显示,但手机仅限于纵向。我找不到任何有条件地选择方向的方法。有什么建议吗?
<?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>
if(getResources().getBoolean(R.bool.portrait_only)){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
最小宽度方向超过600dp的设备,或者在Android 3.2之前的大屏幕设备(基本上是平板电脑),将像正常情况一样表现出来,根据传感器和用户锁定的旋转等。其他所有设备(基本上是手机)只能竖屏显示。
xlarge
和sw600dp
吗?或者只使用sw600dp
就可以了吗?现在可能没有运行版本低于3.2的平板电脑了。 - theblang在Android Studio中,您可以执行以下步骤来添加具有其bools.xml
文件的res/values-sw600dp
和res/values-large
目录。
首先,在导航器中从项目选项卡中选择项目(而不是Android)过滤器。
请右键点击app/src/main/res
目录。选择 新建 > Android 资源目录。在最小屏幕宽度处输入600
。目录名称将自动生成。点击“确定”。
然后右键点击新创建的values-sw600dp
文件。选择新建 > 值资源文件。将名称输入为bools
。
添加values-large
目录仅在支持Android 3.2之前(API级别13)时才是必需的。否则可以跳过此步骤。values-large
目录对应于values-sw600dp
。(values-xlarge
对应于values-sw720dp
。)
要创建values-large
目录,请按照上述步骤操作,但在此情况下选择大小而非最小屏幕宽度。选择大。目录名称将自动生成。
bools.xml
文件。跟随 Ginny 的回答,我认为最可靠的方法是:
按照这里所述,在资源文件夹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
扩展,也必须在您的AndroidManifest.xml文件中为每个Activity
添加行android:configChanges="orientation|screenSize"
:
<activity
android:name=".login.LoginActivity"
android:configChanges="orientation|screenSize">
</activity>
android:configChanges="keyboardHidden|orientation|screenSize"
在每个Activity中添加方法的步骤:
public static boolean isXLargeScreen(Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK)
>= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
and: (如果您不覆盖此方法,应用程序在更改方向时将调用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
}
if (!isXLargeScreen(getApplicationContext())) { //set phones to portrait;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
else {
//I set background images here depending on portrait or landscape orientation
}
唯一我似乎无法弄清楚的是如何在从横向切换到纵向或反之后让应用程序更改布局文件。 我认为答案类似于上面链接所做的事情,但我无法使其对我起作用 - 它删除了所有我的数据。但是,如果您拥有一个足够简单的应用程序,同时具有相同的纵向和横向布局文件,则应该可以使用此方法。
我遇到了提供的解决方案的问题,最终这是对我有用的:
AndroidManifest.xml
中将 Activity 的方向设置为 "locked" :<activity
android:name="com.whatever.YourActivity"
android:screenOrientation="locked"
... />
OnCreate(...)
方法中,使用以下代码:@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)
}
DeviceProperties
类中的isTablet(resources)
方法,该方法除其他事项外还检查smallestScreenWidthDp >= 600
。setRequestedOrientation
。问题在于它设置的方向太晚了,会导致轻微的UI故障。如果您的设备处于横向状态,当您启动应用程序时,它会加载横向屏幕然后旋转。如果您使用主题来创建闪屏效果,则会注意到背景图像的方向错误,这尤其明显。这也可能会影响最近使用的应用程序中如何显示您的应用程序,并且还会引起配置更改方面的问题,正如其他答案评论中所指出的那样。<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>
基本代码*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。
注意:仅适用于通过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
按照已接受的答案,我正在添加包含解决方案的Kotlin文件,希望能帮到某些人。
将此布尔资源放入 res / values
中,命名为bools.xml或其他名称(文件名称在此无关紧要):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="portrait_only">true</bool>
</resources>
将此文件放置于res/values-sw600dp
和res/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)
}
}
从developer.android.com中,您应该在清单文件中使用值“nosensor”声明屏幕方向:
方向不是根据物理方向传感器确定的。忽略传感器,因此显示屏不会根据用户移动设备而旋转。
旋转将是设备的“自然”行为(对于手机:竖屏/对于平板电脑:横屏)。
优点是可以在每个活动中混合不同的旋转方式,例如,如果您有一个显示数据库记录的活动,则可以将此活动方向设置为“fullUser”,而其他活动则使用“nosensor”。 “fullUser”活动将根据用户选择旋转(启用旋转:使用传感器,否则使用用户首选项)。
<activity android:name=".scanner.ScannerPropertiesActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/title_activity_scanner_properties"
android:screenOrientation="${screenOrientation}"/>
${screenOrientation} 是一个 ManifestPlaceHolder,因此我可以使用它轻松地在所有方向行为之间切换我想要测试的所有活动:
//module's build.gradle
defaultConfig {
//...
manifestPlaceholders = [applicationName:appName,screenOrientation:'nosensor']
//...
}
如果您需要更复杂的功能(例如:仅在平板电脑上允许屏幕旋转并将手机方向固定为纵向),那么您应该使用locked:
android:screenOrientation="locked"
我注意到,如果您强制将方向设置为portrait,而传感器发送的是手机横向旋转,则您的Activity将以横向模式启动,然后在执行代码后旋转为纵向模式,几乎可以适用于任何其他方向。
lock会保留先前的旋转状态,因此您可能已经被锁定在先前的纵向模式中。然后,您必须知道设备是平板电脑还是手机:为此,我建议您使用以下内容:
//normal tablet_detection file content:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="isTablet" type="bool">false</item>
</resources>
//sw600dp tablet_detection file content:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="isTablet" type="bool">true</item>
</resources>
//Now in your code you can detect if it's a tablet or not by calling following function in your Activity's **onCreate** and apply screen orientation by code:
protected void updateScreenOrientation(){
boolean isTablet =context.getResources().getBoolean(R.bool.isTablet);
//And select the orientation you wish to set:
int defaultOrientation=isTablet? ActivityInfo.SCREEN_ORIENTATION_FULL_USER:ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
if(getRequestedOrientation()== ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
//Apply this only on Activities where you set the orientation to 'locked' in the manifest
this.setRequestedOrientation(defaultOrientation);
}
}
其他解决方案对我没有用。我仍然遇到了一些奇怪的对话框方向问题和重建问题。我的解决方案是扩展Activity,在清单文件中将其强制设为纵向。
示例:
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);
建议的方法是不要为任何窗口尺寸锁定方向,但您可以按照此处的指南来实现。
步骤上,首先要做的事情是在清单上解锁方向。
<activity
android:name=".MyActivity"
android:screenOrientation="fullUser">
/** Determines whether the device has a compact screen. **/
fun compactScreen(): Boolean {
val screenMetrics = WindowMetricsCalculator
.getOrCreate()
.computeMaximumWindowMetrics(this)
val shortSide = min(screenMetrics.bounds.width(),
screenMetrics.bounds.height())
return shortSide / resources.displayMetrics.density < 600
}
最后,当空间较小时(通常在手机上),您可以锁定方向:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestedOrientation = if (compactScreen())
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else
ActivityInfo.SCREEN_ORIENTATION_FULL_USER
...
}
res
文件夹中使用layout-land
。 - GhostsetRequestedOrientation
一样重新创建Activity:https://dev59.com/questions/A4Xca4cB1Zd3GeqPGlKN#27015879 - guness