最近在做播放器的时候遇到一个问题,在屏幕方向改变之后需要切换播放器全屏/非全屏的时候,在重写了onConfigurationChanged方法并在manifest.xml配置文件中添加
- android:screenOrientation="sensor"
- android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
之后,在屏幕方向改变之后确实切换了播放器的方向,但是在我的程序中,需要一个播放器控制按钮,当用户点击按钮时手动切换播放器方向(即播放器全屏/小屏状态切换)和屏幕方向改变时自动切换两个功能并存;最开始想的是直接使用setRequestedOrientation()设置屏幕方向应该就OK了,但是发现这样做是行不通的.之后了解到因为setRequestedOrientation设置屏幕方向之后,比如说setRequestedOrientation(portrait)方法,就设定了屏幕方向是portrait,和在清单文件中配置android:screenOrientation="portrait"是同等的效果;也即不再响应屏幕方向改变,只支持portrait方向;
言归正转,说我的处理方法,android给我们提供了OrientationEventListener,从字面意思就知道是干什么用的;这个监听器有一个onOrientationChanged(int rotation)方法会将当前屏幕旋转的度数返回给用户;
先看持接口中方法返回的旋转度数的计算方法;
上图中金色区域就是手机,角度就是绿线和红线之间的角度,顺时针旋转手机,角度增大,角度范围0-360;手机平放的角度为-1;
下面分别是横屏和竖屏的界面,按钮即用于切换屏幕方向;
再看看具体实现:
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; } }