锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

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

时间:2023-09-23 23:37:02 6手动方向传感器多少

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的配置和上一次手动设置的影响,我们得到的返回值可能不是上述四个值之一,而是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中,因此会忽略它实际并不是当前页面的横竖屏状态,而是整个设备最顶端页面的横竖屏状态,因此用来检测并根据横竖屏状态切换后台资源是非常可靠的,例如录屏场景下自动切换横竖屏分辨率。

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章