最近在作播放器的时候遇到一个问题,在屏幕方向改变以后须要切换播放器全屏/非全屏的时候,在重写了onConfigurationChanged方法并在manifest.xml配置文件中添加android
android:screenOrientation="sensor"ide
android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"ui
以后,在屏幕方向改变以后确实切换了播放器的方向,可是在个人程序中,须要一个播放器控制按钮,当用户点击按钮时手动切换播放器方向(即播放器全屏/小屏状态切换)和屏幕方向改变时自动切换两个功能并存;最开始想的是直接使用setRequestedOrientation()设置屏幕方向应该就OK了,可是发现这样作是行不通的.以后了解到由于setRequestedOrientation设置屏幕方向以后,好比说setRequestedOrientation(portrait)方法,就设定了屏幕方向是portrait,和在清单文件中配置android:screenOrientation="portrait"是同等的效果;也即再也不响应屏幕方向改变,只支持portrait方向;this
言归正转,说个人处理方法,android给咱们提供了OrientationEventListener,从字面意思就知道是干什么用的;这个监听器有一个onOrientationChanged(int rotation)方法会将当前屏幕旋转的度数返回给用户;spa
先看持接口中方法返回的旋转度数的计算方法;code
上图中金色区域就是手机,角度就是绿线和红线之间的角度,顺时针旋转手机,角度增大,角度范围0-360;手机平放的角度为-1;orm
下面分别是横屏和竖屏的界面,按钮即用于切换屏幕方向;xml
再看看具体实现:接口
1.声明变量事件
private OrientationEventListener mOrientationListener; // 屏幕方向改变监听器 private boolean mIsLand = false; // 是不是横屏 private boolean mClick = false; // 是否点击 private boolean mClickLand = true; // 点击进入横屏 private boolean mClickPort = true; // 点击进入竖屏
2.初始化监听器
/** * 开启监听器 */ private final void startListener() { mOrientationListener = new OrientationEventListener(this) { @Override public void onOrientationChanged(int rotation) { // 设置竖屏 if (((rotation >= 0) && (rotation <= 30)) || (rotation >= 330)) { if (mClick) { if (mIsLand && !mClickLand) { return; } else { mClickPort = true; mClick = false; mIsLand = false; } } else { if (mIsLand) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); mIsLand = false; mClick = false; } } } // 设置横屏 else if (((rotation >= 230) && (rotation <= 310))) { if (mClick) { if (!mIsLand && !mClickPort) { return; } else { mClickLand = true; mClick = false; mIsLand = true; } } else { if (!mIsLand) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mIsLand = true; mClick = false; } } } } }; mOrientationListener.enable(); }
3.设置按钮点击切换屏幕方向响应事件
mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mClick = true; if (!mIsLand) { if (onClickOrientationListener != null) { onClickOrientationListener.landscape(); } setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mIsLand = true; mClickLand = false; } else { if (onClickOrientationListener != null) { onClickOrientationListener.portrait(); } setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); mIsLand = false; mClickPort = false; } } });
4.上面用到一个接口OnClickOrientationListener,里面包含两个方法,分别用于用户点击切换横屏/竖屏时的回调;
interface OnClickOrientationListener { public void landscape(); public void portrait(); }
代码贴完了, 简单说说思路,点击的时候,直接切换屏幕方向,切换以后,须要当手机屏幕也旋转到所切换的方向以后,才又开始监听手机屏幕旋转事件,这样就实现了setRequestedOrientation以后仍然能够经过旋转手机切换屏幕的功能;
举个例子:
-->手机当前是竖屏状态,Activity也是竖屏状态
-->用户点击切换按钮
-->Activity切换为横屏,手机为竖屏;此时经过设置flag,使OrientationListener监听到竖屏时再也不处理事件,waiting...
-->直到当用户把手机旋转为横屏状态以后,更改flag,使OrientationListener监听到竖屏时处理相应的事件
-->当用户再次旋转手机切换为竖屏以后,Activity便可自动切换为竖屏;
横屏点击切换竖屏理论同上;
第三步,用户点击切换按钮以后进入横屏,此时就不响应监听到的竖屏处理事件,而且要等待到第四步用户把手机旋转为横屏状态以后再响应竖屏监听;这样定义彷佛不太合理,但从用户的角度看,不可能用户点击了要进入横屏,却仍然把手机给竖屏方向拿着;
最后,当不须要监听屏幕方向的时候,须要调用OrientationListener.disable()关闭监听器;
小记录一下相关知识01/07/2014
private int getScreenRotation() { WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); try { Method m = display.getClass().getDeclaredMethod("getRotation"); return (Integer) m.invoke(display); } catch (Exception e) { return Surface.ROTATION_0; } } private int getScreenOrientation() { switch (getScreenRotation()) { case Surface.ROTATION_0: return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; case Surface.ROTATION_90: return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; case Surface.ROTATION_180: return (Build.VERSION.SDK_INT >= 8 ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); case Surface.ROTATION_270: return (Build.VERSION.SDK_INT >= 8 ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); default: return 0; } }