Android WebView全屏视频出口创建额外的空白空间

如何解决Android WebView全屏视频出口创建额外的空白空间

我有一个android webapp,我想在其中以隐藏系统栏和导航栏的全屏模式播放视频。一切正常,没有任何问题。

我的MainActivity的原始视图如下图所示。

enter image description here

但是当我从全屏模式退出时,会出现问题。每当我退出全屏视频时,都会创建很少的空白区域。

我尝试过使用YouTube,Vimeo和Dailymotion。但是所有这些站点仍然存在问题。下面我给出了他们的演示,退出全屏模式后的样子。

YouTube:

enter image description here

Vimeo:

enter image description here

DailyMotion:

enter image description here

这是我的 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <ProgressBar
        android:id="@+id/mainProgressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:max="100"
        android:visibility="gone" />

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/mainSrl"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/mainControllerContainer"
        android:layout_below="@id/mainProgressBar">

        <com.jobayr.webapp.ObservableWebView
            android:id="@+id/mainWebView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

    <LinearLayout
        android:id="@+id/mainControllerContainer"
        android:layout_width="match_parent"
        android:layout_height="?actionBarSize"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:orientation="horizontal"
        android:weightSum="4">

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/mainControllerBackBtn"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="?selectableItemBackgroundBorderless"
            android:clickable="true"
            android:focusable="true"
            android:padding="12dp"
            app:srcCompat="@drawable/icon_back" />

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/mainControllerRefreshBtn"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="?selectableItemBackgroundBorderless"
            android:clickable="true"
            android:focusable="true"
            android:padding="12dp"
            app:srcCompat="@drawable/icon_refresh" />

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/mainControllerHomeBtn"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="?selectableItemBackgroundBorderless"
            android:clickable="true"
            android:focusable="true"
            android:padding="12dp"
            app:srcCompat="@drawable/icon_home" />

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/mainControllerForwardBtn"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="?selectableItemBackgroundBorderless"
            android:clickable="true"
            android:focusable="true"
            android:padding="12dp"
            app:srcCompat="@drawable/icon_forward" />

    </LinearLayout>

</RelativeLayout>

MainActivity.kt

class MainActivity : AppCompatActivity(),AdvancedWebView.Listener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        init()
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.mian_menu,menu)
        return super.onCreateOptionsMenu(menu)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (item.itemId == R.id.miClearCookies) {
            AlertDialog.Builder(this)
                .setTitle("Clear Data")
                .setMessage("Are you sure you want to delete browser data?")
                .setPositiveButton("Delete") { _,_ ->
                    WebStorage.getInstance().deleteAllData()
                    CookieManager.getInstance().removeAllCookies(null)
                    CookieManager.getInstance().flush()
                    mainWebView.clearCache(true)
                    mainWebView.clearFormData()
                    mainWebView.clearHistory()
                    mainWebView.clearSslPreferences()
                }
                .setNegativeButton("Cancel",null)
                .show()
        } else if (item.itemId == R.id.miExit) {
            AlertDialog.Builder(this)
                .setTitle("Confirmation")
                .setMessage("Are you sure you want to exit?")
                .setPositiveButton("YES") { _,_ ->
                    finishAffinity()
                }
                .setNegativeButton("CANCEL",null)
                .show()
        }
        return super.onOptionsItemSelected(item)
    }

    override fun onResume() {
        super.onResume()
        mainWebView.onResume()
    }

    override fun onPause() {
        super.onPause()
        mainWebView.onPause()
    }

    override fun onDestroy() {
        super.onDestroy()
        mainWebView.onDestroy()
    }

    override fun onActivityResult(requestCode: Int,resultCode: Int,data: Intent?) {
        super.onActivityResult(requestCode,resultCode,data)
        mainWebView.onActivityResult(requestCode,data)
    }

    private fun init() {
        goOn()
        initCallback()
    }

    private fun goOn() {
        val permissionListener = object : PermissionListener {

            override fun onPermissionGranted() {
                initWebView()
            }

            override fun onPermissionDenied(deniedPermissions: MutableList<String>?) {
                AlertDialog.Builder(this@MainActivity)
                    .setTitle("Permission Required")
                    .setMessage("Kindly grant all the permission to use this app")
                    .setPositiveButton("Retry") { _,_ ->
                        goOn()
                    }
                    .setNegativeButton("Cancel") { _,_ ->
                        finishAffinity()
                    }
                    .show()
            }
        }

        TedPermission.with(this)
            .setPermissionListener(permissionListener)
            .setDeniedMessage("You need to grant all the permission to use this app")
            .setPermissions(
                Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE
            )
            .check()
    }

    @SuppressLint("SetJavaScriptEnabled")
    private fun initWebView() {
        mainWebView.loadUrl(getString(R.string.url),true)
        mainWebView.settings.javaScriptEnabled = true
        mainWebView.setListener(this,this)
        mainWebView.settings.javaScriptCanOpenWindowsAutomatically = true
        mainWebView.webViewClient = WebViewClient()
        mainWebView.settings.setSupportZoom(false)
        mainWebView.settings.displayZoomControls = false
        mainWebView.setCookiesEnabled(true)
        mainWebView.setThirdPartyCookiesEnabled(true)
        mainWebView.setMixedContentAllowed(true)
        mainWebView.webChromeClient = CustomChromeClient(this,mainProgressBar)
    }

    private fun initCallback() {
        mainControllerBackBtn.setOnClickListener {
            if (mainWebView.canGoBack()) {
                mainWebView.goBack()
            } else Toast.makeText(this,"Going Back Is Not Available",Toast.LENGTH_SHORT)
                .show()
        }
        mainControllerRefreshBtn.setOnClickListener {
            mainWebView.reload()
        }
        mainControllerHomeBtn.setOnClickListener {
            mainWebView.loadUrl(getString(R.string.url),true)
        }
        mainControllerForwardBtn.setOnClickListener {
            if (mainWebView.canGoForward()) {
                mainWebView.goForward()
            } else Toast.makeText(this,"Going Forward Is Not Available",Toast.LENGTH_SHORT)
                .show()
        }
        mainSrl.setOnRefreshListener {
            mainWebView.reload()
        }
        mainWebView.setOnScrollChangedCallback { _,t,_,oldt ->
            if (t > oldt) {
                if (t - oldt >= 60) {
                    supportActionBar?.hide()
                    mainControllerContainer.visibility = View.GONE
                }
            } else if (t < oldt) {
                if (oldt - t >= 60) {
                    supportActionBar?.show()
                    mainControllerContainer.visibility = View.VISIBLE
                }
            }
        }
    }

    override fun onKeyDown(keyCode: Int,event: KeyEvent?): Boolean {
        if (event!!.action == KeyEvent.ACTION_DOWN) {
            when (keyCode) {
                KeyEvent.KEYCODE_BACK -> {
                    if (mainWebView.canGoBack()) {
                        mainWebView.goBack()
                    } else {
                        AlertDialog.Builder(this)
                            .setTitle("Confirmation")
                            .setMessage("Are you sure you want to exit?")
                            .setPositiveButton("YES") { _,_ ->
                                finishAffinity()
                            }
                            .setNegativeButton("CANCEL",null)
                            .show()
                    }
                    return true
                }
            }
        }
        return super.onKeyDown(keyCode,event)
    }

    override fun onPageFinished(url: String?) {
        if (mainSrl.isRefreshing) {
            mainSrl.isRefreshing = false
        }
    }

    override fun onPageError(errorCode: Int,description: String?,failingUrl: String?) {
        if (mainSrl.isRefreshing) {
            mainSrl.isRefreshing = false
        }
        description?.let {
            Toast.makeText(this,it,Toast.LENGTH_LONG).show()
        }
    }

    override fun onDownloadRequested(
        url: String?,suggestedFilename: String?,mimeType: String?,contentLength: Long,contentDisposition: String?,userAgent: String?
    ) {
        try {
            if (AdvancedWebView.handleDownload(this,url,suggestedFilename)) {
                Toast.makeText(this,"Download Started",Toast.LENGTH_LONG).show()
            } else {
                AlertDialog.Builder(this)
                    .setTitle("Download Error")
                    .setMessage("Couldn't download ${suggestedFilename}. Make sure your download manager is working properly.")
                    .setPositiveButton("OK",null)
                    .show()
            }
        } catch (e: Exception) {
            AlertDialog.Builder(this)
                .setTitle("Download Error")
                .setMessage(e.message.toString())
                .setPositiveButton("OK",null)
                .show()
        }
    }

    override fun onExternalPageRequest(url: String?) {
        mainWebView.loadUrl(url,true)
    }

    override fun onPageStarted(url: String?,favicon: Bitmap?) {}

}

CustomChromeClient.java

public class CustomChromeClient extends WebChromeClient {

    private Activity activity;
    private ProgressBar progressBar;
    private View mCustomView;
    private WebChromeClient.CustomViewCallback mCustomViewCallback;
    private int mOriginalOrientation;
    private int mOriginalSystemUiVisibility;

    CustomChromeClient(Activity activity,ProgressBar progressBar) {
        this.activity = activity;
        this.progressBar = progressBar;
    }

    public Bitmap getDefaultVideoPoster() {
        if (mCustomView == null) {
            return null;
        }
        return BitmapFactory.decodeResource(activity.getResources(),2130837573);
    }

    @Override
    public void onProgressChanged(WebView view,int newProgress) {
        super.onProgressChanged(view,newProgress);
        if (newProgress < 100) {
            progressBar.setVisibility(View.VISIBLE);
            progressBar.setProgress(newProgress);
        } else {
            progressBar.setVisibility(View.GONE);
            progressBar.setProgress(0);
        }
    }

    public void onHideCustomView() {
        this.mCustomViewCallback.onCustomViewHidden();
        this.mCustomViewCallback = null;
        ((FrameLayout) activity.getWindow().getDecorView()).removeView(this.mCustomView);
        this.mCustomView = null;
        activity.getWindow().getDecorView().setSystemUiVisibility(this.mOriginalSystemUiVisibility);
        activity.setRequestedOrientation(this.mOriginalOrientation);
        activity.getWindow().getDecorView().invalidate();
    }

    public void onShowCustomView(View paramView,WebChromeClient.CustomViewCallback paramCustomViewCallback) {
        if (this.mCustomView != null) {
            onHideCustomView();
            return;
        }
        this.mCustomView = paramView;
        this.mOriginalSystemUiVisibility = activity.getWindow().getDecorView().getSystemUiVisibility();
        this.mOriginalOrientation = activity.getRequestedOrientation();
        this.mCustomViewCallback = paramCustomViewCallback;
        ((FrameLayout) activity.getWindow().getDecorView()).addView(this.mCustomView,new FrameLayout.LayoutParams(-1,-1));
        activity.getWindow().getDecorView().setSystemUiVisibility(3846 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.demo.webapp">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:hardwareAccelerated="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true"
        tools:ignore="AllowBackup,UnusedAttribute">
        <activity
            android:name=".MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize|screenLayout|keyboard|layoutDirection|uiMode">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

OvservableWebView.java 这不是您感兴趣的主题(如果我没记错的话。这主要是为了检测Webview的滚动行为。但是,我正在发布也是如此。)

public class ObservableWebView extends AdvancedWebView {

    private OnScrollChangedCallback mOnScrollChangedCallback;

    public ObservableWebView(final Context context) {
        super(context);
    }

    public ObservableWebView(final Context context,final AttributeSet attrs) {
        super(context,attrs);
    }

    public ObservableWebView(final Context context,final AttributeSet attrs,final int defStyle) {
        super(context,attrs,defStyle);
    }

    @Override
    protected void onScrollChanged(final int l,final int t,final int oldl,final int oldt) {
        super.onScrollChanged(l,oldl,oldt);
        if (mOnScrollChangedCallback != null) mOnScrollChangedCallback.onScroll(l,oldt);
    }

    public OnScrollChangedCallback getOnScrollChangedCallback() {
        return mOnScrollChangedCallback;
    }

    public void setOnScrollChangedCallback(final OnScrollChangedCallback onScrollChangedCallback) {
        mOnScrollChangedCallback = onScrollChangedCallback;
    }

    public static interface OnScrollChangedCallback {
        public void onScroll(int l,int t,int oldl,int oldt);
    }
}

请帮助我解决这个问题。任何解决方案,想法将不胜感激。预先感谢。

解决方法

我找到了解决方案!

您必须使用此存储库中的类:https://github.com/cprcrack/VideoEnabledWebView

这是一个由 Stack Overflow 用户创建的存储库,用于帮助和改进在 Android WebView 中全屏播放 HTML 视频。

您可以在 another user answer

中看到它

这是唯一对我有用的解决方案。

,

我找到了解决方案。

从您的 android:fitsSystemWindows="true" 中删除 RelativeLayout,这将删除视图顶部的空白区域。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-