android 整个页面方向,Android页面方向、角度及旋转小结

本文总结了Android应用在处理页面方向、角度及旋转时遇到的问题和解决方案。通过OrientationEventListener获取传感器角度,但不能直接用于屏幕方向判断。Surface.ROTATION与SCREEN_ORIENTATION分别代表旋转角度和页面方向,二者并不完全对应。错误地尝试根据传感器角度切换页面方向导致问题,最终采用检查设备默认横竖屏状态并结合SCREEN_ORIENTATION设置页面方向。注意,页面横竖屏切换会导致Activity重启,可通过设置android:configChanges避免。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android页面方向、角度及旋转小结

手上的项目原本设计之初是基于手机竖屏的,但由于近期某些订制版本需要适配横屏和默认横屏设备,因此对页面的朝向和角度获取要进行一些研究。其中也踩了不少坑,这里拿出来给大家乐呵乐呵。

从传感器角度讲起

通常,我们会使用OrientationEventListener来获取传感器角度,其一般用法如下:

new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL){

@Override

public void onOrientationChanged(int orientation) {

if (orientation > 350 || orientation < 10) { //0度

} else if (orientation > 80 && orientation < 100) { //90度

} else if (orientation > 170 && orientation < 190) { //180度

} else if (orientation > 260 && orientation < 280) { //270度

}

}

}.enable();

当设备平放时,将返回一个无效值,当设备垂直桌面且与自然状态(即开机时页面的默认方向)一致时,返回0度,所谓自然角度是指系统在编译之初设定的默认角度,有兴趣的同学可以搜索“修改Android系统默认横竖屏”,这里不做赘述。通常对于手机,正常竖屏垂直于桌面时返回0度,对于默认横屏设备则是横屏垂直于桌面时返回0度。

这个角度我在项目中用于对相机回调数据进行旋转、SurfaceView绘制等地方。

Surface.ROTATION

关于页面方向存在两种定义,一种是由Surface类中的声明的ROTATION:

/**

* 转动0度 (自然角度)

*/

public static final int ROTATION_0 = 0;

/**

* 转动90度

*/

public static final int ROTATION_90 = 1;

/**

* 转动180度

*/

public static final int ROTATION_180 = 2;

/**

* 转动270度

*/

public static final int ROTATION_270 = 3;

顾名思义,它是一种旋转角度。而其中的ROTATION_0在注释中(这里为了方便阅读已经翻译,下同)已指明它是页面的自然角度。

当设备平放时,不论启动时默认是横屏还是竖屏状态,它总是以ROTATION_0状态首先展示,其余三个值都是以此为参照进行的旋转角度。

当锁定屏幕方向时,转动手机只会造成传感器角度变化,ROTATION并不会发生变化,这意味着ROTATION总是与页面方向绑定而不与传感器方向绑定。它们的关系仅停留在自然状态下(比如手机竖直放置)ROTATION_0与传感器的0度角一致。

因此我们虽然可以通过getWindowManager().getDefaultDisplay().getRotation();方法来获取当前页面的ROTATION值,但不能以此反推传感器角度,也不能获取屏幕横竖屏状态。

在实际使用时,我用作矫正相机预览角度。

SCREEN_ORIENTATION

上文的另一种定义则是在ActivityInfo中声明的SCREEN_ORIENTATION,我们可以将其与manifest.xml中activity的android:screenOrientation属性相匹配,共有16种,这里我们只取采坑踩到的4种:

/**

* 页面横屏

*/

public static final int SCREEN_ORIENTATION_LANDSCAPE = 0;

/**

* 页面竖屏

*/

public static final int SCREEN_ORIENTATION_PORTRAIT = 1;

/**

* 页面横屏翻转

*/

public static final int SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8;

/**

* 页面竖屏翻转

*/

public static final int SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9;

顾名思义,它是指页面方向,并且这四个值一定是与横竖屏相关联的,ROTATION_0可以是横屏也可以是竖屏,但SCREEN_ORIENTATION_PORTRAIT只会是竖屏,其它同理。

实际开发时我们通过Activity.setRequestedOrientation(int);来手动设置页面方向,虽然可以通过Activity.getRequestedOrientation();来获取方向, 但其返回值受到manifest.xml的配置和上一次手动设置的影响,我们拿到的返回值可能并不是上述4个值之一,而是SCREEN_ORIENTATION_UNSPECIFIED(默认,指跟随系统)、SCREEN_ORIENTATION_SENSOR(跟随传感器)等其它取值,并不能知道其具体朝向。

与Surface.ROTATION相同的是,它也只有一个默认方向在自然角度时是与传感器的0度角相匹配的,不同的是正常来说我们无法获知这个方向的具体值。

错误示范

我的需求是将原本竖屏的应用调整为横屏设备上只允许横屏,竖屏设备只有视频页面允许横竖屏切换且两种状态下界面不一致,在我已经用到了传感器角度的情况下,我很自然的想到能否根据传感器角度主动切换页面具体方向。

于是我在Manifest.xml中把页面方向配置为screenOrientation=‘nosener’,同时根据角度切调用

setRequestedOrientation()设置上面四个值,在手机上由于0度角一定匹配SCREEN_ORIENTATION_PORTRAIT,其余三个方向以此推算,是可以实现的,但到横屏设备上就有问题了,尤其以下两点:

横屏设备的默认朝向不一致,可能是LANDSCAPE也可能是REVERSE_LANDSCAPE,无法对应具体的角度,因此也无法推算其它三个朝向的角度。

部分横屏设备屏蔽SCREEN_ORIENTATION_REVERSE_LANDSCAPE(实际部分手机也屏蔽SCREEN_ORIENTATION_PORTRAIT),因此强制固定一个角度也不可取。

综上,想在所有设备上适用是不可行的,所以还是老老实实的抛开传感器角度,单独使用setRequestedOrientation(int);来实现需求。

方案修正

这次抛开传感器角度交给系统处理,首先我们判断设备是否默认横屏以区分效果,这里Manifest.xml中就不再配置页面方向了,也就是默认的userLandscape,在setContentView调用之前我们通过以下代码判断设备方向:

/**

* 判断设备是否默认横屏设备

*/

public static boolean isLandDevice(Activity activity){

boolean bLand = false;

int orientation = activity.getResources().getConfiguration().orientation;

switch (activity.getWindowManager().getDefaultDisplay().getRotation()){

case Surface.ROTATION_0:

case Surface.ROTATION_180:

bLand = orientation == Configuration.ORIENTATION_LANDSCAPE;

break;

case Surface.ROTATION_90:

case Surface.ROTATION_270:

bLand = orientation != Configuration.ORIENTATION_LANDSCAPE;

break;

default:

break;

}

return bLand;

}

代码很简单不再多说了,拿到默认横竖屏状态之后,我们再来设置页面的朝向。

/**

* 切换页面方向

* @param bLandDevice 是否是默认横屏设备

* @param bVideoPage 是否是视频页

*/

protected void setOrientation(boolean bLandDevice, boolean bVideoPage){

if (bLandDevice){

//Android 4.3及以上允许跟随系统的横屏切换

if (DeviceUtil.isAndroidJELLY_BEAN_MR2()) {

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);

} else {

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);

}

} else {

//视频界面允许全角度

if (bVideoPage){

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

} else {

//部分手机屏蔽竖屏翻转,这里强制只有竖屏

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

}

}

}

目标达成,所以花费了那么多时间到底是为嘛呢,想法太多也不是好事,还是多多走正道比较好,希望大家也能少走些弯路。

值得注意的问题

页面的横竖屏切换是会导致Acitivity重启的,如果不希望重启,在Manifest.xml的activity属性中增加android:configChanges="orientation|screenSize|keyboardHidden|locale"即可。

使用上一条在切换后会回调onConfigurationChanged(Configuration newConfig)方法,其参数只包含了横竖屏状态,没有具体朝向,同时只是横屏切横屏或竖屏切竖屏不会被回调。

相机预览角度必须在切换横竖屏状态后重新设置,此时Surface.ROTATION发生了变化。

额外的知识

上文中用到了Context.getResources().getConfiguration().orientation;

众所周知,它通常只有Configuration.ORIENTATION_LANDSCAPE和Configuration.ORIENTATION_PORTRAIT两个取值分别代表横竖屏状态。

由于使用场景通常在onConfigurationChanged中,因此会忽略它实际并不是当前页面的横竖屏状态,而是整个设备最顶端页面的横竖屏状态,因此用来检测并根据横竖屏状态切换后台资源是非常可靠的,例如录屏场景下自动切换横竖屏分辨率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值