我希望平板电脑能够显示肖像和景观(sw600dp或更大),但手机仅限于肖像。我找不到任何有条件地选择方向的方法。有什么建议吗?
当前回答
下面是使用资源和大小限定符的好方法。
将这个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中添加这些目录和文件的帮助,请参阅补充答案。
然后,在你的活动的onCreate方法中,你可以这样做:
if(getResources().getBoolean(R.bool.portrait_only)){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
在最小宽度方向上超过600dp的设备,或者在android 3.2之前的设备(基本上是平板电脑)上的x-large设备将会像正常的设备一样,基于传感器和用户锁定旋转等。其他所有东西(手机,几乎)都只能是竖屏。
其他回答
建议的方法是不锁定任何窗口维度的方向,但您可以通过遵循这里的指南来实现。
在步骤中,要做的第一件事是解锁舱单上的方向
<activity
android:name=".MyActivity"
android:screenOrientation="fullUser">
接下来,你可以使用Jetpack窗口管理器来确定应用程序在屏幕上有多少空间:
/** 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
...
}
根据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>
我在提供的解决方案中遇到了一些问题,最后这对我来说是有效的:
在AndroidManifest.xml中设置Activity的方向为“锁定”:
<activity
android:name="com.whatever.YourActivity"
android:screenOrientation="locked"
... />
在Activity中的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)
}
注意,你不需要在资源中使用布尔值的hack解决方案,你可以使用DeviceProperties类中的isTablet(资源)方法,除了其他东西之外,它检查是否smallstscreenwidthdp >= 600。
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
下面是使用资源和大小限定符的好方法。
将这个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中添加这些目录和文件的帮助,请参阅补充答案。
然后,在你的活动的onCreate方法中,你可以这样做:
if(getResources().getBoolean(R.bool.portrait_only)){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
在最小宽度方向上超过600dp的设备,或者在android 3.2之前的设备(基本上是平板电脑)上的x-large设备将会像正常的设备一样,基于传感器和用户锁定旋转等。其他所有东西(手机,几乎)都只能是竖屏。
推荐文章
- 警告:API ' variable . getjavacompile()'已过时,已被' variable . getjavacompileprovider()'取代
- 安装APK时出现错误
- 碎片中的onCreateOptionsMenu
- TextView粗体通过XML文件?
- 如何使线性布局的孩子之间的空间?
- DSL元素android.dataBinding。enabled'已过时,已被'android.buildFeatures.dataBinding'取代
- ConstraintLayout:以编程方式更改约束
- PANIC: AVD系统路径损坏。检查ANDROID_SDK_ROOT值
- 如何生成字符串类型的buildConfigField
- Recyclerview不调用onCreateViewHolder
- Android API 21工具栏填充
- Android L中不支持操作栏导航模式
- 如何在TextView中添加一个子弹符号?
- PreferenceManager getDefaultSharedPreferences在Android Q中已弃用
- 在Android Studio中创建aar文件