2014-12-05 47 views
1

我有一个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文档。通过$(“身体”)

  1. 装入包装
  2. 包装加载实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加载了真正的文档体之后。这样的加载顺序 - >光标绘制都按正确的顺序进行。解决了。

+0

解决了我自己的问题 - 查看更新的问题文本。 – Scotty 2014-12-06 13:33:57

+0

请考虑发布一个实际的答案,为社区着想,并解决它。 – Ercan 2015-01-21 09:20:29

回答

0

如更新问题(加入这个答案,所以我可以解决这个)提到:

在事后解决这个问题是相当明显的:我用我在其中加载各种JS一个“包装”的html文件库 - JSQuery,Rangy等,并在其中我使用JSQuery来替换文档正文与我想要加载/阅读的'真正'的HTML文档。因此,从HTML文档的角度来看,加载发生在两个阶段:

加载包装 包装加载真正的HTML文档通过$(“body”)。load(“”) 由于这两个阶段加载,我的应用程序看到Webview.onPageFinished事件被触发 - 但这只是表明加载的包装HTML,而不是全身。所以我需要做的就是在JSQuery .load方法成功完成后,从我的webview/javascript向应用添加一个明确的调用。