WebView 支持 Html5 video 进行全屏播放及横竖屏自动切换
1.检查AndroidManifest.xml清单文件,WebView控件所在的Activity配置信息;检查Activity的主题是否NoActionBar了。
## 犯错的错误写成了如下: android:configChanges="orientation|keyboardHidden" -->
## 正确的写法: android:configChanges="orientation|screenSize|keyboardHidden"
或者: android:configChanges="keyboard|keyboardHidden|orientation|screenSize|navigation|fontScale|uiMode|screenLayout"
注:
总结:
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
(一次生命周期)如切换成横屏: onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->
2.初始化webview及各项setting(自己去根据需求初始化)
//常用:
WebSettings ws = webView.getSettings();
// 网页内容的宽度是否可大于WebView控件的宽度
ws.setLoadWithOverviewMode(false);
// 保存表单数据
ws.setSaveFormData(true);
// 是否应该支持使用其屏幕缩放控件和手势缩放
ws.setSupportZoom(true);
ws.setBuiltInZoomControls(true);
ws.setDisplayZoomControls(false);
// 启动应用缓存
ws.setAppCacheEnabled(true);
// 设置缓存模式
ws.setCacheMode(WebSettings.LOAD_DEFAULT);
// setDefaultZoom api19被弃用
// 设置此属性,可任意比例缩放。
ws.setUseWideViewPort(true);
// 不缩放
webView.setInitialScale(100);
// 告诉WebView启用JavaScript执行。默认的是false。
ws.setJavaScriptEnabled(true);
// 页面加载好以后,再放开图片
ws.setBlockNetworkImage(false);
// 使用localStorage则必须打开
ws.setDomStorageEnabled(true);
// 排版适应屏幕
ws.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
// WebView是否新窗口打开(加了后可能打不开网页)
ws.setSupportMultipleWindows(true);
// webview从5.0开始默认不允许混合模式,https中不能加载http资源,需要设置开启。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ws.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
/** 设置字体默认缩放大小(改变网页字体大小,setTextSize api14被弃用)*/
ws.setTextZoom(100);
3.给WebView设置WebViewClient:
思路:在onShowCustomView方法中,讲获取到的view放到当前Activity的最上方,在onHideCustomView中,将之前的view隐藏或者删除,将原来被覆盖的webview放回来。并结束播放。
webView.setWebViewClient(new MyWebViewClient(this));
//webview视频全屏下videoContainer ---(自己在webview所在布局里定义一个frameLayout作为盛放view的容器) private CustomVideoContainerFramLayout mVideoContainer; //webview全屏时传入的view private View mXCustomView; public class NewsWebViewChromeClient extends WebChromeClient { /** * webview全屏回调 * * @param view * @param callback */ @Override public void onShowCustomView(View view, CustomViewCallback callback) { super.onShowCustomView(view, callback); //设置全屏 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //设置横屏 int requestedOrientation = getRequestedOrientation(); if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) { //反横屏下设置跟随传感器 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); } else { //其他情况设置横屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } if (webview != null) { webview.setVisibility(View.GONE); } if (mXCustomView != null) { callback.onCustomViewHidden(); return; } fullViewAddView(view); mXCustomView = view; mVideoContainer.setVisibility(View.VISIBLE); //设置隐藏虚拟按键/导航键(避免造成全屏时布局不满) mXCustomView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE); } /** * webview 退出全屏回调 */ @Override public void onHideCustomView() { if (mXCustomView == null) { // 不是全屏播放状态 return; } //取消全屏 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); //恢复虚拟键 mXCustomView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); //恢复为用户方向 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER); mXCustomView.setVisibility(View.GONE); if (mVideoContainer != null) { mVideoContainer.removeView(mXCustomView); } mXCustomView = null; mVideoContainer.setVisibility(View.GONE); if (webview != null) { webview.setVisibility(View.VISIBLE); } } } public void fullViewAddView(View view) { FrameLayout decor = (FrameLayout) getWindow().getDecorView(); mVideoContainer = new CustomVideoContainerFramLayout(this); mVideoContainer.addView(view); decor.addView(mVideoContainer); }
开启重力感应自动切换屏幕
使用方法:
//重力传感器
private MySensorHelper sensorHelper;
private void initData() {
//初始化重力感应,传入activity
sensorHelper = new MySensorHelper(this);
//开启重力感应
sensorHelper.enable();
}
@Override
protected void onDestroy() {
//关闭重力传感器
if (sensorHelper != null) {
sensorHelper.disable();
}
}
4.开启重力感应自动切换屏幕
使用方法:
//重力传感器
private MySensorHelper sensorHelper;
private void initData() {
//初始化重力感应,传入activity
sensorHelper = new MySensorHelper(this);
//开启重力感应
sensorHelper.enable();
}
@Override
protected void onDestroy() {
//关闭重力传感器
if (sensorHelper != null) {
sensorHelper.disable();
}
}
直接上代码:具体可根据需求进行更改
/**
* @author : Created by zhangqiang
* @date : on 2018/9/30.
* desc :通过重力传感器切换横竖屏放向
* 在activity的ondestory()方法里面或者back键的监听里面禁用屏幕监听
*/
public class MySensorHelper {
private static final String TAG = "MySensorHelper";
private OrientationEventListener mOrientationEventListener;
private WeakReference<Activity> mActivityWeakRef;
private Activity mActivity;
//竖直锁定
private boolean isPortLock = false;
//横屏锁定
private boolean isLandLock = false;
//是否在全屏模式
private boolean isFullScreen = false;
//屏幕方向
private int mOrientation = -1;
//屏幕状态 (横屏 / 竖屏等)
private ScreenState mScreenState;
public MySensorHelper(final Activity activity) {
this.mActivityWeakRef = new WeakReference(activity);
mActivity = activity;
//横屏感应
this.mOrientationEventListener = new OrientationEventListener(activity, SensorManager.SENSOR_DELAY_NORMAL) {
@Override
public void onOrientationChanged(int orientation) {
if (BuildConfig.DEBUG) {
Log.v(MySensorHelper.TAG, "mOrientationEventListener:" + orientation);
}
// //若未开启重力感应则不作处理
// if (!ishaveSensor()) {
// return;
// }
//横屏感应
if (orientation < 100 && orientation > 80 || orientation < 280 && orientation > 260) {
if (!MySensorHelper.this.isLandLock) {
Activity mActivity = (Activity) MySensorHelper.this.mActivityWeakRef.get();
if (mActivity != null) {
if (orientation < 280 && orientation > 260) {
/* 在全屏模式下 或者 开启了重力感应下 才进入旋转 */
if (isFullScreen || ishaveSensor()) {
//设置横屏
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
if (BuildConfig.DEBUG) {
Log.w(MySensorHelper.TAG, "转到了横屏##################");
}
}
} else if (orientation < 100 && orientation > 80) {
//在全屏模式下 或者 开启了重力感应下 才进入旋转
if (isFullScreen || ishaveSensor()) {
//设置反向横屏
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
if (BuildConfig.DEBUG) {
Log.w(MySensorHelper.TAG, "转到了横屏-反向 ##################");
}
}
}
isLandLock = true;
isPortLock = false;
}
}
}
// 竖屏感应
if (orientation < 10 || orientation > 350 || orientation < 190 && orientation > 170) {
if (!MySensorHelper.this.isPortLock) {
Activity mActivity = (Activity) MySensorHelper.this.mActivityWeakRef.get();
if (mActivity != null) {
if (isFullScreen) {
//全屏下 若未开启方向锁定 调用webview全屏消失
if (mScreenState != null && ishaveSensor()) {
mScreenState.OnScreenPortrait();
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
if (BuildConfig.DEBUG) {
Log.w(MySensorHelper.TAG, "全屏下 转到了竖屏!!!!!!!!!!!!!!!!!!!!!!");
}
}
} else {
//非全屏下才处理 感应旋转
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
if (BuildConfig.DEBUG) {
Log.w(MySensorHelper.TAG, "非全屏下 转到了竖屏!!!!!!!!!!!!!!!!!!!!!!");
}
}
isPortLock = true;
isLandLock = false;
}
}
}
}
};
}
/**
* 禁用切换屏幕的开关
*/
public void disable() {
Log.e(TAG, "disable");
//禁用横屏感应
if (mOrientationEventListener != null) {
this.mOrientationEventListener.disable();
}
}
/**
* 开启横竖屏切换的开关
*/
public void enable() {
//横屏感应
if (mOrientationEventListener != null) {
this.mOrientationEventListener.enable();
}
}
/**
* 设置竖屏是否上锁,true锁定屏幕,fanle解锁
*
* @param lockFlag
*/
public void setPortLock(boolean lockFlag) {
this.isPortLock = lockFlag;
}
/**
* 设置横屏是否锁定,true锁定,false解锁
*
* @param isLandLock
*/
public void setLandLock(boolean isLandLock) {
this.isLandLock = isLandLock;
}
/**
* 设置当前是否全屏
*
* @param fullScreen
*/
public void setFullScreen(boolean fullScreen) {
this.isFullScreen = fullScreen;
}
/**
* 获取系统重力感应的开关状态
* 0表示关闭,1表示开启
*/
public boolean ishaveSensor() {
int sensor = 0;
try {
sensor = Settings.System.getInt(mActivity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
if (sensor == 0) {
return false;
} else {
return true;
}
}
/**
* Activity当前屏幕方向的属性值
*
* @return 0 横屏 , 1 竖屏
*/
public int getOrientation() {
if (mActivity != null && !mActivity.isFinishing()) {
mOrientation = mActivity.getResources().getConfiguration().orientation;
return mOrientation;
}
return -1;
}
/**
* 设置Activity的的屏幕方向属性值
*
* @param orientation ActivityInfo.xxx 0 横屏 , 1 竖屏 如ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
* <p>
* screenOrientations属性共有7中可选值(常量定义在 .ActivityInfo类中 ) :
* 0-landscape:横屏(风景照) ,显示时宽度大于高度;
* portrait:竖屏 (肖像照) , 显示时 高 度大于 宽 度 ;
* user:用户当前的首选方向;
* behind:继承Activity堆栈中当前Activity下面的那个Activity的方向;
* sensor:由物理感应器决定显示方向,它取决于用户如何持有设备,当 设备 被旋转时方向会随之变化——在横屏与竖屏之间;
* nosensor:忽略物理感应器——即显示方向与物理感应器无关,不管用户如何旋转设备显示方向都不会随着改变("unspecified"设置除外);
* unspecified :未指定,此为默认值,由Android系统自己选择适当的方向,选择策略视具体设备的配置情况而定,因此不同的设备会有不同的方向选择;
* 以上配置值会反映在Activity.getRequestedOrientation()方法的返回值中,与之对应的setRequestedOrientation()方法可以通过API的方式动态改变该属性的值,如以下示例将在横屏/竖屏两个方向上进行切换
*/
public void setOrientation(int orientation) {
mOrientation = orientation;
mActivity.setRequestedOrientation(orientation);
}
/**
* 设置屏幕状态(横屏/竖屏监听)
*
* @param screenState
*/
public void setScreenStateListener(ScreenState screenState) {
mScreenState = screenState;
}
/**
* 屏幕状态接口类
*/
public interface ScreenState {
/**
* 竖屏状态
*/
void OnScreenPortrait();
}
}