放大KitKat WebView后不再有Text Reflow

时间:2013-11-14 19:13:06

标签: android webview android-webview android-4.4-kitkat page-zoom

我有一个严重依赖WebView的应用程序。 在KitKat更新后,用户报告该应用在放大或缩小后不再重排文本。 我查看了文档并发现很多内容已经发生了变化,但是虽然它有很多关于缩放和缩放的内容,但没有任何关于文本重排的内容。似乎一旦设置了视口,缩放就是一个全缩放的东西,并且不再有选项可以在缩放后重新进行文本重排。 有没有解决方案呢?

6 个答案:

答案 0 :(得分:10)

KitKat Chromium WebView不会重排文本。如果您担心文本易读性,请参阅migration guide中的“NARROW_COLUMNS和SINGLE_COLUMN不再支持”部分,其中建议的解决方案是使用文本自动调整。

如果你真的想要带回这个效果那么你需要做这样的事情:

  1. 将您的所有内容都放在<div id="contentRoot"> </div>
  2. 实施onScaleChanged

    class MyWebViewClient extends WebViewClient {
        boolean scaleChangedRunnablePending = false;
    
        // Other code here
    
        @Override
        void onScaleChanged(final WebView webView, fload oldScale, float newScale) {
            if (scaleChangedRunnablePending) return;
            view.postDelayed(new Runnable() {
                @Override
                public void run() {
                    webView.evaluateJavaScript("recalculateWidth();", null);
                    scaleChangedRunnablePending = false;
                }
            }, 100);
        }
    }
    
    // Don't forget to webView.setWebViewClient(new MyWebViewClient());
    
  3. 使用以下JavaScript

    function recalculateWidth() {
        $("#contentRoot").width(window.innerWidth);
    }
    

    或者,您也可以尝试修改视口元标记。

  4. 以上应该稍微延迟执行回流(这是为了将不必要的重新布局数量降至最低)。

答案 1 :(得分:5)

谢谢大家,为这个伟大的线程!!我想加我的2cents。 无需在HTML文件中添加id ='contentRoot'的额外div。您可以使用 body 标记,该标记必须已存在于任何html中。另外,正如EladAvron所写,JS代码可以直接从Java调用。总而言之,marcin.kosiba发布的原始答案适用于您无权修改的HTML。

对我有用的JS调用是:

webview.loadUrl("javascript:document.getElementsByTagName('body')[0].style.width=window.innerWidth+'px';");

我不知道为什么,但添加'px'对我来说至关重要。

答案 2 :(得分:1)

感谢这些提示 - 结合它们,我发现以下解决方法不需要Java:

var innerWidth = 0;
var text_reflow = function () {
  if (window.innerWidth != innerWidth) {
    innerWidth = window.innerWidth;
    document.getElementsByTagName('body')[0].style.width = innerWidth+'px';
  }
};
text_reflow();
setInterval(text_reflow, 500);

不是使用轮询间隔,而是可以做,例如

window.onresize = text_reflow;
addListener(window, 'touchstart', function (e) { text_reflow(); });

不幸的是,似乎无法捕捉到实际的缩放到缩放事件。

答案 3 :(得分:1)

这是一个旧线程,但我只想添加我正在使用的解决方案,以防有人可能从中受益。在完全缩放时,我在某些页面上遇到了奇怪的缩放问题,不幸的是,如果页面一直缩小,在JavaScript中很难检测到。解决方案是在调整页面大小之前检测规模变化是否足够大。

以下解决方案适用于KitKat和Lollipop,没有令人讨厌的逐渐缩小,这是我在某些网站上看到的。

class MyWebViewClient extends WebViewClient {
    private boolean mIsRunning = false;
    private float mZoomScale = 0.0f;
    private static final String REFLOW_TEXT = "javascript:document.getElementsByTagName('body')[0].style.width=window.innerWidth+'px';"

    @Override
    public void onScaleChanged(final WebView view, final float oldScale, final float newScale) {
        if (view.isShown() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            if (mIsRunning)    // Don't run if there's a resize runnable in the queue
                return;
            if (Math.abs(mZoomScale - newScale) > 0.01f) {    // This stops the gradual zoom
                mIsRunning = view.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mZoomScale = newScale;
                        view.evaluateJavascript(REFLOW_TEXT, null);
                        mIsRunning = false;
                    }
                }, 100);
            }
        }
    }
}

感谢marcin.kosiba和user3185518,他们将我的解决方案结合起来并进行了修改以构建这个答案。

答案 4 :(得分:0)

此代码将确保100%解决您的问题 KitKat的问题 来得很好 头

  

<meta name="viewport" content="maximum-scale=0"> java> view.evaluateJavascript("document.getElementsByTagName('head')[0].appendChild('<meta name=\"viewport\" content=\"maximum-scale=0\">');", null);

webView.setWebViewClient(new WebViewClient() {
            boolean scaleChangedRunnablePending = false;
            @Override
            public void onScaleChanged(final WebView view, float oldScale, float newScale) {
                super.onScaleChanged(view, oldScale, newScale);
                if (scaleChangedRunnablePending) return;
                view.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        view.evaluateJavascript("document.getElementsByTagName('head')[0].appendChild('<meta name=\"viewport\" content=\"maximum-scale=0\">');", null);
                        scaleChangedRunnablePending = false;
                    }
                }, 100);
            }

答案 5 :(得分:0)

使用JavaScript中的window.innerWidth的答案应在Android 4.4(适用于WebView的Chrome 33)上运行,但不适用于某些较新的Android版本。这是因为Chrome 48和Chrome 61+缩放时window.innerWidth保持不变(请参见Chrome issue 571297),这会影响所有Android 9设备以及某些Android 5至8设备,具体取决于对Android System WebView的更新用户已接受。

Chrome 61+上的替代品是Visual Viewport API,它提供了window.visualViewport.width,因此现在应将使用window.innerWidth的答案更新为使用(window.visualViewport!=undefined?window.visualViewport.width:window.innerWidth),以实现最大的兼容性。