Android中Katex MathView的WebView OnPageFinished函数未触发问题
解决MathView中WebView的onPageFinished未触发问题
我之前也碰到过WebView加载本地/静态内容时onPageFinished不触发的情况,结合你用的MathView(基于KaTeX的WebView封装),大概率是因为它通过本地HTML+JS渲染数学公式,而非加载网络URL,导致WebView的onPageFinished没有按预期触发。下面给你几个可行的解决方案:
方案一:监听WebView的加载进度(最直接)
WebChromeClient的onProgressChanged能更可靠地捕获加载完成的时机,当进度到100时,基本可以确定内容已经加载并渲染完成。你可以替换原来的WebViewClient设置:
final MathView mWebView = view.findViewById(R.id.mathViewExplanation); mWebView.setWebChromeClient(new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); if (newProgress == 100) { // 用post确保视图测量完成,避免获取到不准确的高度 view.post(() -> { Toast.makeText(getActivity(), "height:" + view.getMeasuredHeight(), Toast.LENGTH_SHORT).show(); Log.e("WebView Progress:", mWebView.getProgress() + " "); MoveButton(view.findViewById(R.id.cardViewNext), convertPixelsToDp(view.getMeasuredHeight(), getContext())); }); } } });
方案二:利用JS回调捕获KaTeX渲染完成时机
因为MathView本质是用KaTeX的JS库渲染公式,我们可以在渲染完成后通过JS接口通知Android端,这是最精准的方式:
- 先定义一个JS回调接口类:
class MathRenderCallback { @JavascriptInterface public void onRenderFinished() { // 切换回UI线程执行操作 getActivity().runOnUiThread(() -> { mWebView.post(() -> { Toast.makeText(getActivity(), "height:" + mWebView.getMeasuredHeight(), Toast.LENGTH_SHORT).show(); Log.e("WebView Progress:", mWebView.getProgress() + " "); MoveButton(mWebView.findViewById(R.id.cardViewNext), convertPixelsToDp(mWebView.getMeasuredHeight(), getContext())); }); }); } }
- 给MathView添加JS接口,并修改渲染逻辑:
// 添加JS接口 mWebView.addJavascriptInterface(new MathRenderCallback(), "MathCallback"); // 如果MathView通过加载包含KaTeX的HTML渲染,在HTML末尾添加触发回调的代码: // <script>katex.render(你的公式内容, 目标元素).then(() => window.MathCallback.onRenderFinished())</script>
如果MathView源码已经封装了KaTeX渲染逻辑,你可以修改它的loadMath相关方法,在KaTeX渲染完成的Promise回调里触发我们的JS接口。
方案三:监听视图布局变化作为兜底
如果上面两种方法都不适用,可以通过ViewTreeObserver监听MathView的布局变化,当它的高度稳定后执行MoveButton:
final MathView mWebView = view.findViewById(R.id.mathViewExplanation); ViewTreeObserver vto = mWebView.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 移除监听,避免多次触发 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { mWebView.getViewTreeObserver().removeOnGlobalLayoutListener(this); } else { mWebView.getViewTreeObserver().removeGlobalOnLayoutListener(this); } Toast.makeText(getActivity(), "height:" + mWebView.getMeasuredHeight(), Toast.LENGTH_SHORT).show(); Log.e("WebView Progress:", mWebView.getProgress() + " "); MoveButton(mWebView.findViewById(R.id.cardViewNext), convertPixelsToDp(mWebView.getMeasuredHeight(), getContext())); } });
为什么onPageFinished没触发?
Android WebView的onPageFinished在加载本地数据(比如loadData/loadDataWithBaseURL)时,经常会出现触发不及时或者不触发的情况,因为本地内容不需要网络请求,WebView可能会提前标记加载完成,但此时JS渲染(比如KaTeX)还在进行,导致你的MoveButton无法拿到正确的视图高度。
内容的提问来源于stack exchange,提问作者Shatrujeet Naruka
相关产品推荐
相关产品推荐

