我有一个Android应用程序,它使用KitKat级别的WebView来显示文档(主要是作为一个电子阅读器消耗HTML文件)。当用户在应用程序中打开一个文档(因此webview因此为该文档重新实例化)时,我想滚动到文档中最后一个已知的光标位置,以便用户可以从他们离开的位置继续阅读。很明显,我保留并坚持web浏览器的光标位置,以便在我第一次打开文档时进行滚动。Android的webview不会始终打开到最后滚动位置
问题: 当文档第一次打开时,我可以看到最后已知的位置(光标)的初始突出我的JavaScript文件中,但随后的情况下,也许50%是我见过的文件莫名其妙地向后翻页到顶部,所以光标位置不再显示。在这些情况下,如何以及为什么滚动回顶端对我来说是个谜(我不相信我会以任何方式让它滚动回顶端)。
注意: 为了实现webview中的滚动我使用了一个javascript函数,它从webview片段(通过webview.loadUrl)调用,一旦webview发出信号,它已加载并准备使用。这是从文档视图片段回调web视图:
\t @TargetApi(Build.VERSION_CODES.KITKAT) @SuppressLint("ClickableViewAccessibility") @Override
\t public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
\t { \t \t
\t \t View mainView = inflater.inflate(R.layout.document_webview_reader, container, false);
\t \t getReaderActivity().setFooterLocationBarValues(mainView);
\t \t
\t \t mWebviewLoading = true;
\t \t final WebView webview = (WebView) mainView.findViewById(R.id.document_webReader_webView);
\t \t webview.getSettings().setJavaScriptEnabled(true);
\t \t webview.getSettings().setAllowFileAccessFromFileURLs(true);
\t \t webview.getSettings().setAllowUniversalAccessFromFileURLs(true);
\t \t webview.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
\t \t webview.setBackgroundColor(0);
\t \t webview.setBackgroundColor(Color.LTGRAY);
\t \t
\t \t if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
\t \t {
\t \t WebView.setWebContentsDebuggingEnabled(true);
\t \t }
\t \t
\t \t mJsInterface = new JsCall();
\t \t webview.addJavascriptInterface(mJsInterface, mJsInterface.getInterfaceName());
\t \t
\t \t webview.setWebViewClient(new WebViewClient()
\t \t { \t \t \t
\t \t \t public void onPageFinished(WebView view, String url)
\t \t \t {
\t \t \t \t drawInitialCursor(getDocument().getCursorRange()); \t \t \t \t \t \t
\t \t \t }
\t \t });
\t \t
\t private void drawInitialCursor(final WordRange range)
\t {
\t \t if(getReaderActivity().activityIsPaused()) return;
\t
\t \t getActivity().runOnUiThread(new Runnable()
\t \t {
\t \t \t
\t \t \t @Override
\t \t \t public void run()
\t \t \t {
\t \t \t \t Log.d(ReaderApplication.VDREADER_TAG,"highlighting initial range");
\t \t \t \t WordRange currentFragmentRange = mTextFragmentRanges.get(mCurrentTextFragmentIndex);
\t \t \t \t int relativeLocation = range.getLocation() - currentFragmentRange.getStartRange();
\t \t \t \t WordRange rangeInCurrentFragment = new WordRange(relativeLocation, range.getLength());
\t \t \t \t \t \t
\t \t \t \t WebView webview = (WebView) getActivity().findViewById(R.id.document_webReader_webView);
\t \t \t \t
\t \t \t \t String applyString = String.format("javascript:highlightInitialRange(%d,%d,%d,%d)",
\t \t \t \t \t \t rangeInCurrentFragment.getStartRange(),rangeInCurrentFragment.getEndRange(),
\t \t \t \t \t \t mCurrentTextFragmentIndex,
\t \t \t \t \t \t mCursorPositionSetting.ordinal());
\t \t \t \t webview.loadUrl(applyString);
\t \t \t }
\t \t });
\t }
关于 'highlightInitialRange' 的JavaScript是:
function highlightInitialRange(start, end, elementIndex, cursorPagePositionSetting)
{
if(wordHighlightApplier == null) {
wordHighlightApplier = rangy.createClassApplier("voice-dream-spoken-word",
{ elementTagName: "vdword"}
);
}
if(selRange == null) {
selRange = rangy.createRange();
}
wordHighlightApplier.undoToRange(selRange);
var \t myNodelist = document.querySelectorAll(VD_cssSelector);
selRange.selectCharacters(myNodelist[elementIndex], start, end);
wordHighlightApplier.applyToRange(selRange);
var wordCursor = document.getElementsByTagName("vdword");
wordCursor[0].scrollIntoView(true);
}
以上的JavaScript基本上只是找到文件中的相关范围(如a元素索引和该元素内的偏移量的组合),向其应用突出显示(通过rangy),然后将突出显示的元素滚动到视图中。
正如我所说,我知道这种策略通常工作,因为我总是可以看到它突出显示正确的位置,当文档加载和Web视图准备使用;但在大约50%的时间里,我运行这个程序时,我看到光标短暂高亮显示,然后随着文档滚动回顶端(假设光标范围超出了文档的初始页面),它会消失。
**我会在这里发布正确光标高亮的图像,但显然我没有足够的信誉来允许这样的琐事。 **
问题: 我在这里错过了关于webview文档渲染的内容吗?我知道一切工作正确,就突出显示和突出显示的元素的初始滚动视图而言,并且我只在webview完全加载后(通过webview客户端上的onPageFinished通知)执行此突出显示代码。 webview本身是否存在一些当文档完全加载时非确定性执行的内容,以确保文档显示在其最上方的滚动位置?
***议决由业主
在事后解决这个问题是相当明显的:我用我在其中加载各种JS库一“包装” html文件 - JSQuery,四肢瘦长等,以及内我正在使用JSQuery将文档正文替换为我要加载/读取的“真实”html文档。通过$(“身体”)
- 装入包装
- 包装加载实HTML文档加载(“”)
由于这种两阶段加载,我的应用程序正在看到Webview.onPageFinished事件被触发 - 但这只是表示加载包装器html,而不是完整的正文。因此,所有我需要做的是从我的web视图/ javascript来的应用程序添加的显式调用一旦JSQuery .load方法已成功地完成:
<body>
<script>
$("body").load("%s", function(response, status, xhr)
{
if (status == "error")
{
var msg = "Sorry but there was an error: ";
$("#error").html(msg + xhr.status + " " + xhr.statusText);
}
else
{
// append our line highlight div, floating
var newDiv = $("<div id='vd-spoken-line' class='voice-dream-spoken-line'/>");
$("body").append(newDiv);
notifyDocumentBodyLoaded(); <-- new callback to android app here
}
});
</script>
</body>
所以后来“notifyDocumentBodyLoaded”执行了Android /以前在onPageFinished方法中执行的java代码,但只有在JSQuery加载了真正的文档体之后。这样的加载顺序 - >光标绘制都按正确的顺序进行。解决了。
解决了我自己的问题 - 查看更新的问题文本。 – Scotty 2014-12-06 13:33:57
请考虑发布一个实际的答案,为社区着想,并解决它。 – Ercan 2015-01-21 09:20:29