Android WebView 音频播放控制 & 视频全屏播放

需求 1

播放是没有问题的,主要是退出页面,或者当前页面 onPause 时,要停止音乐播放

解决方案

找了好久解决方案,以下仅就我所用到且有用的,做记录:
自定义 WebView,先实例化,注册监听

    private fun audioWebViewControl() {
        audioManager = context?.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        listener = AudioManager.OnAudioFocusChangeListener {
//            when (it) {
//                AudioManager.AUDIOFOCUS_LOSS -> ToastUtils.showShortToast(context, "loss")
//                AudioManager.AUDIOFOCUS_GAIN -> ToastUtils.showShortToast(context, "gain")
//            }
        }
    }

争夺音频输出的控制权(这是WebView中的 onPause 方法)

    override fun onPause() {
        var i = 0
        do {
            val result = audioManager?.requestAudioFocus(listener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
            if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
                break
            }
            i++
        } while (i < 10)
        super.onPause()
    }

需求 2

要求富文本中的视频可以全屏播放,调用的是 WebView 内核原生的视频播放器

遇到的小插曲
  1. PC可以正常全屏播放,而Android端不展示 全屏按钮
    private lateinit var rootView: FrameLayout
    fun initView(content: String, rootView: FrameLayout) {
        initView(content, null)
        this.rootView = rootView
    }
 webChromeClient = (object : WebChromeClient() {
            override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
                super.onShowCustomView(view, callback)
                customView = view
                customViewCallback = callback
//                ToastUtils.showShortToast(context, "show")
                visibility = View.GONE
                rootView.addView(customView)
            }

            override fun onHideCustomView() {
                super.onHideCustomView()
                if (customViewCallback != null) {
//                    ToastUtils.showShortToast(context, "hide")
                    customViewCallback!!.onCustomViewHidden()
                    visibility = View.VISIBLE
                    rootView.removeView(customView)
                }
            }
        })

或者

 webChromeClient = (object : WebChromeClient() {
            override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
                super.onShowCustomView(view, callback)
                customView = view
                customViewCallback = callback
                rootView.addView(customView)

            }

            override fun onHideCustomView() {
                super.onHideCustomView()
                if (customViewCallback != null) {
                    rootView.removeView(customView)
                }
            }
        })

设置完成就可以展示出来了,需要注意的是:
一定要先实例化 WebChromeClient,否则有可能仍不展示

        webChromeClient = WebChromeClient()

小技巧

可能上述已经解决大部分问题。但是我遇到了特殊情况:

页面结构

现在我在最底层,也就是单个子任务页,其父容器也就是ViewPage,未铺满全屏且自适应高度。当我将最外层布局 传入时,就将ViewPage撑了1.5个屏左右,且向上滑动还有其他内容区。

怎么能让视频全屏的时候浮在所有的view上面,而不随着全屏拉伸内容区呢?
即使是在多层嵌套的最底层。

解决

灵感来自传入的类型 FrameLayout
我忽然意识到整个View树的最顶端就是 FrameLayout ,也就是 DecorView

    fun initView(content: String, rootView: FrameLayout) {
        initView(content, null)
        this.rootView = rootView
    }

于是,问题迎刃而解,所谓 以无厚入有间,恢恢乎其于游刃必有余地矣。

    wv_task_sub_topic.initView(it, activity!!.window.decorView as FrameLayout)

项目中用到的地方

//  设置题干富文本
     subtaskEntity.description?.let {
//   需要在父容器中展示,而不是当前view,所以传入 DecorView 会让全屏播放脱离父view的束缚
         wv_task_sub_topic.initView(it, activity!!.window.decorView as FrameLayout)
     }

传入 DecorView 会让全屏播放脱离父view的束缚,这是没有错的,但是又遇到了新的问题。

后续补充(2018/10/09)

忽略了个别机型的 Navigation Bar (导航栏)。
DecorView 是包含 Navigation Bar (导航栏) 的,
**全屏后会出现被 导航栏 遮挡 退出全屏的按钮,而无法退出全屏。
固然可以通过各种测量来解决导航栏的问题,但我们应从根源上解决问题!

传入一个不包含导航栏的父View不就可以了?这就是答案!

Window的RootView,表示当前应用程序的有效高度。即去掉状态栏和导航栏后的高度;

// 获取方式
activity!!.window.findViewById(Window.ID_ANDROID_CONTENT)

最后修改代码如下:

//        设置题干富文本
        subtaskEntity.description?.let {
            //            需要在父容器中展示,而不是当前view,所以传入 DecorView 会让全屏播放脱离父view的束缚
//            wv_task_sub_topic.initView(it, activity!!.window.decorView as FrameLayout)
            wv_task_sub_topic.initView(it, activity!!.window.findViewById(Window.ID_ANDROID_CONTENT) as FrameLayout)
        }

附自定义WebView代码

/**
 * 
 *     author : jake
 *     time   : 2018/07/31
 *     function   :  webview 简装
 *     version: 1.0
 * 
*/ class TaskTitleWebView(context: Context?, attrs: AttributeSet? = null) : WebView(context, attrs) { private lateinit var rootView: FrameLayout private var customViewCallback: WebChromeClient.CustomViewCallback? = null private var customView: View? = null private var audioManager: AudioManager? = null private lateinit var listener: AudioManager.OnAudioFocusChangeListener fun initView(content: String) { initView(content, null) } fun initView(content: String, rootView: FrameLayout) { initView(content, null) this.rootView = rootView } @SuppressLint("SetJavaScriptEnabled") fun initView(content: String, callBack: WebViewClientCallBack?) { audioWebViewControl() setBackgroundColor(0) //设置背景色 background.alpha = 0 //设置填充透明度(布局中一定要设置background,不然getbackground会是null) val webSettings = settings webSettings.javaScriptEnabled = true webSettings.builtInZoomControls = true webSettings.displayZoomControls = false scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY //取消滚动条白边效果 webViewClient = WebViewClient() webChromeClient = WebChromeClient() webSettings.defaultTextEncodingName = "UTF-8" webSettings.blockNetworkImage = false // loadData(content, "text/html", "UTF-8") loadData(content, "text/html; charset=UTF-8", null) webChromeClient = (object : WebChromeClient() { override fun onShowCustomView(view: View?, callback: CustomViewCallback?) { super.onShowCustomView(view, callback) customView = view customViewCallback = callback // ToastUtils.showShortToast(context, "show") visibility = View.GONE rootView.addView(customView) } override fun onHideCustomView() { super.onHideCustomView() if (customViewCallback != null) { // ToastUtils.showShortToast(context, "hide") customViewCallback!!.onCustomViewHidden() visibility = View.VISIBLE rootView.removeView(customView) } } }) } override fun onPause() { var i = 0 do { val result = audioManager?.requestAudioFocus(listener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT) if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { break } i++ } while (i < 10) super.onPause() } private fun audioWebViewControl() { audioManager = context?.getSystemService(Context.AUDIO_SERVICE) as AudioManager listener = AudioManager.OnAudioFocusChangeListener { // when (it) { // AudioManager.AUDIOFOCUS_LOSS -> ToastUtils.showShortToast(context, "loss") // AudioManager.AUDIOFOCUS_GAIN -> ToastUtils.showShortToast(context, "gain") // } } } }

你可能感兴趣的:(Android WebView 音频播放控制 & 视频全屏播放)