1. 程式人生 > >WebView網頁視訊統一全屏播放及橫豎屏切換

WebView網頁視訊統一全屏播放及橫豎屏切換

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中可選值(常量定義在 android.content.pm.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();
    }
}

相關參考: