2014-12-05 2 views
1

저는 주로 HTML 파일을 사용하는 e- 리더로 문서를 표시하기 위해 KitKat 수준의 WebView를 사용하는 Android 앱이 있습니다. 사용자가 앱 내에서 문서를 열면 (따라서 웹보기가 해당 문서에 대해 새로 인스턴스화 됨) 문서 내에서 마지막으로 알려진 커서 위치로 스크롤하여 사용자가 중단 한 곳에서 읽을 수 있도록합니다. 분명히 나는 ​​문서를 열 때 그러한 스크롤을 허용하기 위해 웹 뷰의 커서 위치를 indepedently 유지하고 유지한다.안드로이드 webview는 마지막 스크롤 위치에서 일관되게 열리지 않습니다.

문제점 : 문서가 처음 열리면 내 javascript 문서에서 마지막으로 알려진 위치 (커서)의 초기 강조 표시를 볼 수 있지만 그 중 50 %는 문서를 어떻게 든 본 뒤로 스크롤합니다. 커서 위치가 더 이상 표시되지 않습니다. 어떻게 그리고 왜 이런 경우에 맨 위로 스크롤 하는가는 나에게 수수께끼이다 (나는 프로그래밍 방식으로 어떤 식 으로든 맨 위로 스크롤하도록 만든다.)

NOTES : webview에서 스크롤을 수행하려면 webview가로드되고 사용할 준비가되었음을 알리면 webview 조각 (webview.loadUrl을 통해)에서 호출되는 javascript 함수를 사용하고 있습니다.

\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'의 자바 스크립트는 :

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); 
 

 
    }

상기 스크립트 이것은 웹보기에 문서 뷰 단편에서 콜백이고 기본적으로 문서에서 관련 범위를 찾습니다 (해당 요소 내에서 요소 색인과 오프셋의 조합)을 사용하여 강조 표시 한 다음 (강조 표시를 통해) 강조 표시된 요소를보기로 스크롤합니다.

제가 말했듯이이 전략은 일반적으로 문서가로드되고 웹보기를 사용할 준비가되었을 때 올바른 위치를 강조 표시 할 수 있기 때문에 일반적으로 작동합니다. 하지만 이것을 실행하는 시간의 50 %에서 커서가 잠깐 강조 표시되고 문서가 맨 위로 스크롤 될 때 사라집니다 (커서 범위가 문서의 처음 페이지를 넘었다 고 가정).

** 나는 정확한 커서 하이라이트 이미지를 여기에 올릴 것이나 분명히 나는 ​​그런 사소한 일을 허용 할만큼 평판이 나쁘다. **

질문 : 여기 webview 문서 렌더링에 관한 것이 누락 되었습니까? 하이라이팅과 하이라이트 된 요소에 대한 초기 scroll-into-view의 관점에서 모든 것이 올바르게 작동한다는 것을 알고 있으며 일단 웹뷰가 완전히로드되면 강조 표시 코드를 실행합니다 (webview 클라이언트에서 onPageFinished를 통해 통지 됨). 문서가 맨 위의 스크롤 위치에 표시되도록 문서가 완전히로드 될 때 비 결정적으로 실행되는 무언가가 webview 자체에 있습니까? 나는 다양한 JS 라이브러리를로드하는 '래퍼'HTML 문서 사용되었다 - 등 JSQuery, 돌아 다니기에 알맞은를, 그리고 내 :

***

이 지나고 나서이 문제에 대한 해결은 매우 명백했다

소유자에 의해 해결 JSext를 사용하여 문서 본문을로드/읽기를 원하는 '실제'html 문서로 대체했습니다.그래서보기의 HTML 문서 지점에서 로딩이 두 단계에서 발생했다 :

  1. 로드 래퍼
  2. 래퍼로드 실제 HTML 문서를 $ ("몸")를 통해 부하 ("")
.

이 2 단계 로딩 때문에 내 앱에서 Webview.onPageFinished 이벤트가 발생하는 것을보고 있었지만 이는 전체 본문이 아닌 래퍼 HTML의로드를 알리는 신호였습니다.

<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'안드로이드를 실행하십시오 JSQuery의 .load 방법이 성공적으로 완료 한 후 그래서 내가 할하는 데 필요한 모든 앱에 내 웹보기/자바 스크립트에서 명시 적으로 호출을 추가했다/자바 코드는 이전에 onPageFinished 메소드에서 실행되었지만 JSQuery에 의해 실제 문서 본문이로드 된 후에 만 ​​가능합니다. 이렇게하면로드 순서 -> 커서 그리기 순서가 올바른 순서로 발생합니다. 해결 됐어.

(이 대답을 추가하는 것은 그래서 나는이 문제를 해결할 수) 업데이트 된 질문에서 언급 한 바와 같이
+0

내 자신의 문제를 해결했습니다. 업데이트 된 질문 텍스트를 참조하십시오. – Scotty

+0

커뮤니티를 위해 실제 답변을 게시하고 해결하십시오. – Ercan

답변

0

:

이 지나고 나서이 문제에 대한 해결은 매우 명백했다 : 나는 다양한 JS를로드하는 '래퍼'HTML 문서를 사용했다 라이브러리 - JSQuery, Rangy 등, 그리고 그 안에서 JSQuery를 사용하여 문서 본문을로드/읽기를 원하는 '실제'html 문서로 대체했습니다. 그래서보기의 HTML 문서 지점에서 로딩이 두 단계에서 발생했다 :

로드 래퍼 래퍼는 $ ("몸")를 통해 실제 HTML 문서를로드로드 ("") 를이 때문에 두 단계의. 로드 중, 내 애플 리케이션은 Webview.onPageFinished 이벤트가 해고되는 것을보고 있었다 - 그러나 이것 만이 전신이 아닌 래퍼 HTML의 로딩을 알렸다. 그래서 JSQuery .load 메서드가 성공적으로 완료되면 내 webview/javascript에서 앱에 명시 적 호출을 추가해야했습니다.

관련 문제