最近公司在做一个软件,用户要求软件能随着手机转动自动切换横屏和竖屏,而且要求就算是手机头下脚上的倒个个软件也要能自适应的变成合适的方向。熟悉android的人都知道,android系统的手机绝大部分只支持三种屏幕方向的重力感应自动切换,竖直,水平,反方向水平,独独不支持反方向竖直的重力感应切换。我由于一次偶然刷系统刷到了cm,发现这个系统居然支持竖直方向的重力感应屏幕自动切换,于是我想,这说明系统肯定是支持这个功能的,只是被屏蔽了起来而已。于是我就想,可不可以在源码里找到时哪里被屏蔽了,那我们就可以同过java的反射来调用相关的方法来改变这个设置,让手机支持反方向竖直的重力感应屏幕自动切换,找了很久,可能是我找代码的能力太差,始终没有找到相关的设置代码,倒是意外的发现了activity原来本身就有设置屏幕方向的接口提供,而且四个方向都可以设置,另外还发现一段根据重力感应来计算屏幕方向的方法,两个结合起来,实现竖直方向的重力感应屏幕自动切换的方法就有了,自己监视重力感应来控制屏幕的旋转。
Activity中设置屏幕方向的方法是setRequestedOrientation(int);这个方法接收一个整数,这个整数的值由ActivityInfo的常量类提供,如果像我一样喜欢更新帮助文档的人就会发现文档里面有SCREEN_ORIENTATION_REVERSE_PORTRAIT这么一个变量,可是当你想在代码用的时候代码提示却告诉你这个变量不能被识别(如果是2.2或以下sdk的话,2.3没试过),这个时候我们只好用他原始值9来代替了,把传给setRequestedOrientation方法,屏幕就会被设置成竖直倒转了。
怎么设置屏幕方向的方法有了,那么接下来就是给程序注册一个重力感应的监视器了,这里我们要用到是类型为TYPE_ACCELEROMETER的感应器,有两点需要注意的就是一监视重力感应的变化是个比较耗资源的事情,所以在界面不可见的时候要把监视器注销掉,这个可以在activity的onPause方法里操作,同样的,要保证界面可见的时候要及时的注册监视器,这个放在activity的onResume方法里操作;二是默认activity在旋转屏幕的时候会把原来的activity退出,重新打开一个新的activity,为了避免用户数据丢失我们可能希望直接把屏幕旋转过来但是不关闭已有的activit,这就需要在activity的配置属性里加上这么一项:android:configChanges="orientation|keyboard"
这样就能保证activity在旋转的时候不会关闭了。
实现这个功能最关键的一段代码是根据感应监听器SensorEventListener的onSensorChanged方法传人的SensorEvent类型的对象的值来计算出一个旋转角度。TYPE_ACCELEROMETER的感应器有三个轴,当手机水平放置,屏幕朝上的时候是该感应器的初始状态,这个时候,y轴和x轴的值都是0,而z轴的值是-9.8m/s.当手机转动时三个轴的值都会相应的变化,变化规律可以参考sdk文档的sensorEvent类。所以我们如果要计算出旋转角度的话要综合考虑三个轴的值,这涉及到物理学的一些知识,我这里取了些巧,直接把android源码中计算的代码拿了过来。
今天很杯具的发现这个方法在2.3是可以的,但是在2.2或一下系统就不灵了。。。。
如果需要源码可以到下面这个地址下载:/source/3324066
原创文章,如需转载请注明出处。
如发现任何不对或者可以改进的地方也请指正,能发现不足才能不断进步。