家有两猫~ 2026-02-06 14:18 采纳率: 0%
浏览 2

wed离线预览word

麻烦大家看下是不是哪里设置错误,竖屏状态下有问题
错误显示效果:(竖屏状态)

img


正确显示效果:(横屏状态)

img

代码:


package com.example.luilibrary.view

import android.graphics.Bitmap
import android.os.Build
import android.view.ViewGroup
import android.webkit.ConsoleMessage
import android.webkit.PermissionRequest
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
import androidx.activity.ComponentActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.example.luilibrary.LuiConstant
import com.example.luilibrary.utils.FileUtil

/**
 * @类名: WebFileView
 * &
 * @编码人: Administrator
 * &
 * @日期: 2026/2/4
 * &
 * @描述: web方式文件查看器
 **/
class WebFileView : LifecycleEventObserver {

    private var webView: WebView? = null
    private var filePath: String = ""
    private var VUE_URL_WORD: String = "file:///android_asset/dist/index.html#/word"


    // TODO: 2026/2/4 15:17 -(Administrator)-{🎉  生命周期}

    constructor(context: ComponentActivity) {
        this.webView = WebView(context)
        context.lifecycle.addObserver(this)
    }

    constructor(context: Fragment) {
        this.webView = context.activity?.let { WebView(it) }
        context.lifecycle.addObserver(this)
    }

    override fun onStateChanged(
        source: LifecycleOwner,
        event: Lifecycle.Event
    ) {
        when (event) {
            Lifecycle.Event.ON_RESUME -> if (this.webView != null) {
                this.webView!!.onResume()
            }

            Lifecycle.Event.ON_PAUSE -> if (this.webView != null) {
                this.webView!!.onPause()
                this.webView!!.clearCache(true)
            }

            Lifecycle.Event.ON_DESTROY -> if (this.webView != null) {
                this.webView!!.loadDataWithBaseURL(null, "", "text/html", "utf-8", null)
                this.webView!!.clearHistory()
                (this.webView!!.parent as ViewGroup).removeView(this.webView)
                this.webView!!.destroy()
                this.webView = null
            }

            else -> {}
        }
    }

    // TODO: 2026/2/4 15:18 -(Administrator)-{🎉  内部调用}

    private fun loadWordView() {
        val scp: String?
        if (FileUtil.isWordUrl(this.filePath)) {
            scp = "javascript:openWord(\'${this.filePath}\')"
        } else {
            var word_path = "file://${this.filePath}"
            if (word_path.contains("#")) {
                word_path = word_path.replace("#".toRegex(), "%23")
            }
            scp = "javascript:openWord(\'$word_path\')"
        }
        this.webView!!.evaluateJavascript(scp, ValueCallback { value: String? ->

        })
    }

    private fun apply() {
        WebView.setWebContentsDebuggingEnabled(true)
        val webSettings = this.webView!!.settings
        webSettings.apply {
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
                mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
            }
            allowFileAccess = true
            allowContentAccess = true
            allowFileAccessFromFileURLs = true
            allowUniversalAccessFromFileURLs = true
            javaScriptEnabled = true
            javaScriptCanOpenWindowsAutomatically = true
            cacheMode = WebSettings.LOAD_DEFAULT
            useWideViewPort = true
            loadWithOverviewMode = true
            layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL
            setSupportZoom(true)
            builtInZoomControls = true
            displayZoomControls = false
            defaultFontSize = 12
        }

        webView?.isHorizontalScrollBarEnabled = false
        webView?.scrollBarStyle = WebView.SCROLLBARS_OUTSIDE_OVERLAY
        webView?.isScrollbarFadingEnabled = false

        val extension = ".${FileUtil.getFile(filePath).extension}"
        if (LuiConstant.Companion.DocumentSuffix.isSuffixExist(extension)) {
            this.webView?.loadUrl(VUE_URL_WORD);
        }

        this.webView?.setWebChromeClient(object : WebChromeClient() {
            override fun onPermissionRequest(request: PermissionRequest) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (request.getOrigin().toString() == "file:///") {
                        request.grant(request.getResources())
                    } else {
                        request.deny()
                    }
                }
            }

            override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean {
                return super.onConsoleMessage(consoleMessage)
            }
        })
        this.webView?.setWebViewClient(object : WebViewClient() {
            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
                view.loadUrl(url)
                return true
            }

            override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                super.onPageStarted(view, url, favicon)
            }

            override fun onReceivedError(
                view: WebView?,
                request: WebResourceRequest?,
                error: WebResourceError
            ) {
                super.onReceivedError(view, request, error)
            }

            override fun onReceivedHttpError(
                view: WebView?,
                request: WebResourceRequest?,
                errorResponse: WebResourceResponse
            ) {
                super.onReceivedHttpError(view, request, errorResponse)
            }

            override fun onPageFinished(view: WebView?, url: String?) {
                super.onPageFinished(view, url)
                if (FileUtil.isWordUrl(this@WebFileView.filePath) || LuiConstant.Companion.DocumentSuffix.isSuffixExist(
                        extension
                    )
                ) {
                    loadWordView()
                }
            }
        })
    }

    // TODO: 2026/2/4 15:38 -(Administrator)-{🎉  外部调用}

    fun setFilePath(filePath: String): WebFileView {
        this.filePath = filePath
        return this
    }

    fun attachTo(parent: FrameLayout) {
        apply()
        parent.addView(this.webView)
    }
}
  • 写回答

1条回答 默认 最新

  • 檀越@新空间 2026-02-06 14:19
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    根据你提供的代码和问题描述,你的 WebFileView 类用于在 Android 中通过 WebView 预览 Word 文档。你在 竖屏状态下 遇到显示异常,而在 横屏状态 下正常。这通常与 WebView 的布局设置、屏幕方向、以及 HTML 内容的响应式设计有关


    ✅ 问题分析

    1. 竖屏与横屏差异:

      • 竖屏时,屏幕宽度较窄,可能导致 Web 内容无法正确缩放。
      • 横屏时,宽屏下内容可以更好地适配,因此显示正常。
    2. 可能的原因:

      • useWideViewPort = trueloadWithOverviewMode = true 设置不正确或未生效。
      • WebView 的默认缩放行为在不同方向上表现不一致。
      • HTML 页面本身未做响应式设计,导致在竖屏下布局错乱。
    3. 代码中缺失部分:

      • 你提供的代码中 apply() 方法被截断,缺少了 WebView 的初始化和加载逻辑。
      • 你没有展示 VUE_URL_WORD 的实际内容(例如 HTML 文件),所以无法判断其是否支持响应式布局。

    🔧 解决方案

    1. 调整 WebView 的布局设置

    确保以下设置正确,并且在 所有屏幕方向下都能生效

    val webSettings = this.webView!!.settings
    webSettings.apply {
        // 允许 JS 执行
        javaScriptEnabled = true
    
        // 启用视口缩放
        useWideViewPort = true
        loadWithOverviewMode = true
    
        // 支持缩放
        setSupportZoom(true)
        builtInZoomControls = true
        displayZoomControls = false
    
        // 允许文件访问
        allowFileAccess = true
        allowContentAccess = true
        allowFileAccessFromFileURLs = true
        allowUniversalAccessFromFileURLs = true
    
        // 保持缓存
        cacheMode = WebSettings.LOAD_DEFAULT
    
        // 布局算法
        layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL
    
        // 默认字体大小
        defaultFontSize = 16
    }
    

    重点: useWideViewPort = trueloadWithOverviewMode = true 是关键设置,它们让 WebView 自动适应内容的宽度。


    2. 添加屏幕方向监听器

    确保在屏幕方向变化时重新加载页面或调整 WebView 设置:

    webView?.setOnConfigurationChangedListener { newConfig ->
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            webView?.loadUrl(VUE_URL_WORD)
        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
            webView?.loadUrl(VUE_URL_WORD)
        }
    }
    

    注意: 这个监听器需要在 onCreateonResume 中注册,否则不会生效。


    3. 在 HTML 页面中添加响应式样式

    如果你的 HTML 页面是通过 file:///android_asset/... 加载的,请确保该 HTML 文件包含如下 CSS 样式,以适配竖屏:

    <style>
        body {
            width: 100%;
            max-width: 100%;
            margin: 0;
            padding: 0;
        }
    
        .content {
            width: 100%;
            overflow-x: hidden;
        }
    
        @media (max-width: 600px) {
            .content {
                font-size: 14px;
            }
        }
    </style>
    

    重点: 如果 HTML 页面本身没有响应式设计,那么在竖屏下可能会出现布局错乱。


    4. 修复 loadWordView() 方法中的 URL 编码问题

    当前你使用的是:

    var word_path = "file://${this.filePath}"
    if (word_path.contains("#")) {
        word_path = word_path.replace("#".toRegex(), "%23")
    }
    scp = "javascript:openWord(\'$word_path\')"
    

    但这种写法可能会导致路径错误,建议改为:

    val encodedPath = Uri.encode(this.filePath)
    scp = "javascript:openWord('${encodedPath}')"
    

    重点: 使用 Uri.encode() 可以避免特殊字符(如 #)引起的问题。


    5. 补充完整 apply() 方法

    你提供的 apply() 方法被截断,应补充为:

    private fun apply() {
        WebView.setWebContentsDebuggingEnabled(true)
    
        val webSettings = this.webView!!.settings
        webSettings.apply {
            // 上述已提到的配置...
        }
    
        // 设置 WebViewClient
        this.webView!!.webViewClient = object : WebViewClient() {
            override fun shouldOverrideUrlLoading(
                view: WebView?,
                request: WebResourceRequest?
            ): Boolean {
                return false
            }
    
            override fun onReceivedError(
                view: WebView?,
                request: WebResourceRequest?,
                error: WebResourceError?
            ) {
                super.onReceivedError(view, request, error)
                // 处理加载错误
            }
        }
    
        // 设置 WebChromeClient
        this.webView!!.webChromeClient = object : WebChromeClient() {
            override fun onConsoleMessage(message: String?, sourceID: String?, lineNumber: Int, messageID: Long) {
                // 控制台输出调试信息
            }
    
            override fun onPermissionRequest(request: PermissionRequest?) {
                request?.grant(arrayOf("android.permission.READ_EXTERNAL_STORAGE"))
            }
        }
    
        // 加载初始 URL
        this.webView!!.loadUrl(VUE_URL_WORD)
    }
    

    ✅ 总结

    | 问题 | 解决方案 | |------|----------| | 竖屏下布局错乱 | 设置 useWideViewPort = trueloadWithOverviewMode = true | | 屏幕方向变化导致问题 | 添加 OnConfigurationChangedListener 监听器 | | HTML 页面未响应式 | 在 HTML 中添加媒体查询样式 | | URL 编码错误 | 使用 Uri.encode() 替代字符串替换 | | apply() 方法缺失 | 完善 apply() 方法,包括 WebViewClient 和 WebChromeClient |


    📌 最终建议

    • 确保你使用的 HTML 文件是经过测试的响应式页面。
    • 如果你使用的是第三方库(如 docxtemplatermammoth.js),请检查其文档,看是否支持竖屏显示。
    • 如果问题仍然存在,建议提供完整的 HTML 文件内容,以便进一步排查。

    如需帮助,欢迎继续提供更多信息!

    评论

报告相同问题?

问题事件

  • 创建了问题 2月6日