javascript - Android webview wont consistently open to last-scroll location -


i have android app uses kitkat-level webview display documents (primarily e-reader consumes html files). when user opens document within app (and webview newly instantiated document) want scroll last known cursor location within document, user can pick reading left off. retain , persist cursor location indepedently of webview allow such scrolling when first open document.

problem: when document first opens, can see initial highlighting of last known location (cursor) in javascript document, in perhaps 50% of cases i've seen document somehow scrolls top , cursor location no longer shown. how , why scrolls top in these cases mystery me (i dont believe programatically make scroll top in way).

notes: achieve scrolling within webview i'm using javascript function invoked webview fragment (via webview.loadurl) once webview has signalled has loaded , ready use. callback document view fragment webview:

	@targetapi(build.version_codes.kitkat) @suppresslint("clickableviewaccessibility") @override  	public view oncreateview(layoutinflater inflater, viewgroup container, bundle savedinstancestate)  	{		  		view mainview = inflater.inflate(r.layout.document_webview_reader, container, false);  		getreaderactivity().setfooterlocationbarvalues(mainview);  		  		mwebviewloading = true;  		final webview webview = (webview) mainview.findviewbyid(r.id.document_webreader_webview);  		webview.getsettings().setjavascriptenabled(true);  		webview.getsettings().setallowfileaccessfromfileurls(true);   		webview.getsettings().setallowuniversalaccessfromfileurls(true);  		webview.setscrollbarstyle(view.scrollbars_inside_overlay);  		webview.setbackgroundcolor(0);  		webview.setbackgroundcolor(color.ltgray);  		  		if(build.version.sdk_int >= build.version_codes.kitkat)   		{  		    webview.setwebcontentsdebuggingenabled(true);  		}  		  		mjsinterface = new jscall();  		webview.addjavascriptinterface(mjsinterface, mjsinterface.getinterfacename());  		  		webview.setwebviewclient(new webviewclient()  		{			  			public void onpagefinished(webview view, string url)  			{  				drawinitialcursor(getdocument().getcursorrange());						  			}  		});  		    	private void drawinitialcursor(final wordrange range)  	{  		if( getreaderactivity().activityispaused() ) return;      	  		getactivity().runonuithread(new runnable()  		{  			  			@override  			public void run()  			{  				log.d(readerapplication.vdreader_tag,"highlighting initial range");  				wordrange currentfragmentrange = mtextfragmentranges.get(mcurrenttextfragmentindex);  				int relativelocation = range.getlocation() - currentfragmentrange.getstartrange();  				wordrange rangeincurrentfragment = new wordrange(relativelocation, range.getlength());  						  				webview webview = (webview) getactivity().findviewbyid(r.id.document_webreader_webview);  				  				string applystring = string.format("javascript:highlightinitialrange(%d,%d,%d,%d)",   						rangeincurrentfragment.getstartrange(),rangeincurrentfragment.getendrange(),   						mcurrenttextfragmentindex,  						mcursorpositionsetting.ordinal());    				webview.loadurl(applystring);  			}  		});  	}

the javascript 'highlightinitialrange' is:

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	mynodelist = document.queryselectorall(vd_cssselector);            selrange.selectcharacters(mynodelist[elementindex], start, end);          wordhighlightapplier.applytorange(selrange);            var wordcursor = document.getelementsbytagname("vdword");          wordcursor[0].scrollintoview(true);        }

the above javascript finds relevant range in document (as combination of element index , offset within element), applies highlight (via rangy) , scrolls highlighted element view.

as know strategy works since can see highlighting correct location when document loaded , webview ready use; in ~50% of times run this, see cursor highlight briefly , disappears document scrolled top (assuming cursor range beyond initial page of document of course).

** post image of correct cursor highlight here apparently i'm not reputable enough allow such triviality. **

question: missing webview document rendering here? know working correctly in terms of highlighting , initial scroll-into-view highlighted element, , i'm executing highlighting code once webview loaded (notified via onpagefinished on webview client). there within webview non-deterministically executing when document loaded ensure document displayed @ top-most scroll position?

*** resolved owner

in hindsight resolution problem obvious: using 'wrapper' html document in loaded various js libraries - jsquery, rangy etc, , within using jsquery replace document body 'real' html document want load/read. html document point of view loading occurring in 2 phases:

  1. load wrapper
  2. wrapper loads real html document via $("body").load("")

because of two-phase loading, app seeing webview.onpagefinished event being fired - signalled loading of wrapper html, not full body. needed add explicit call webview / javascript app once jsquery .load method had completed successfully:

<body>  <script>      $( "body" ).load( "%s", function( response, status, xhr )      {          if (status == "error")          {              var msg = "sorry there 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 android app here          }      });  </script>  </body>

so 'notifydocumentbodyloaded' executes android/java code formerly executed in onpagefinished method, after true document body has been loaded jsquery. way sequence of loading -> cursor drawing happens in correct order. solved.

as mentioned in updated question (adding answer can resolve this):

in hindsight resolution problem obvious: using 'wrapper' html document in loaded various js libraries - jsquery, rangy etc, , within using jsquery replace document body 'real' html document want load/read. html document point of view loading occurring in 2 phases:

load wrapper wrapper loads real html document via $("body").load("") because of two-phase loading, app seeing webview.onpagefinished event being fired - signalled loading of wrapper html, not full body. needed add explicit call webview / javascript app once jsquery .load method had completed successfully.


Comments

Popular posts from this blog

python - mat is not a numerical tuple : openCV error -

c# - MSAA finds controls UI Automation doesn't -

wordpress - .htaccess: RewriteRule: bad flag delimiters -