i have an url which has in the html body the following style:
style='width:468px; height:60px;'
I want to add the url in a webview but its content is to big (witdh and height) so i have to resize both.
I tried these solutions(Android Webview - Webpage should fit the device screen, http://developer.android.com/guide/webapps/targeting.html) and no one worked for me. I managed to change the width using:
String javascript = "javascript:document.getElementsByTagName('div')[0].style.width='100%';";
view.loadUrl(javascript);
but it does not work with the height beucase the content is too big. Do you know other ways to do this?
finally i changed the sizes by using the following method:
#Override
public void onPageFinished(WebView view, String url) {
float scale = myWebView.getHeight() / 170f;
myWebView.setInitialScale((int) (scale * 100f));
String js = "javascript:(function(){"
+ "document.getElementsByTagName('div')[0].style.height = 'auto';"
+ "document.getElementsByTagName('div')[0].style.width = 'auto';"
+ "})()";
view.loadUrl(js);
}
Related
Usually after using Google to search for a city, there is a part of Wikipedia page on the right with an image and a map. Can anyone tell me how I could access this image? I should know how to download it.
Actually the main image (that goes with the map image on the right) is very rarely from Wikipedia, so you can't use Wikipedia API to get it. If you want to access the actual main image you can use this:
private static void GetGoogleImage(string word)
{
// make an HTTP Get request
var request = (HttpWebRequest)WebRequest.Create("https://www.google.com.pg/search?q=" + word);
request.UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36";
using (var webResponse = (HttpWebResponse)request.GetResponse())
{
using (var reader = new StreamReader(webResponse.GetResponseStream()))
{
// get all images with base64 string
var matches = Regex.Matches(reader.ReadToEnd(), #"'data:image/jpeg;base64,([^,']*)'");
if (matches.Count > 0)
{
// get the image with the max height
var bytes = matches.Cast<Match>()
.Select(x => Convert.FromBase64String(x.Groups[1].Value.Replace("\\75", "=").Replace("\\075", "=")))
.OrderBy(x => Image.FromStream(new MemoryStream(x, false)).Height).Last();
// save the image as 'image.jpg'
using (var imageFile = new FileStream("image.jpg", FileMode.Create))
{
imageFile.Write(bytes, 0, bytes.Length);
imageFile.Flush();
}
}
}
}
}
This work for me, and always returns the actual main image (if such exists). For example, GetGoogleImage("New York") give me data:image/jpeg;base64,/9j/4AAQSkZJRg....
I use the fact that from the all base64 string images in response the main has the max height, so its need only to order them by height and to select the last one. If it's required, you can check here also for minimum image height. The replacing \075 to = is needed base64's padding.
If you want Wikipedia article main image you have to use Wikipedia API.
Update:
You can use jsoup: Java HTML Parser org.jsoup:jsoup:1.8.3 which return list of image inside page.
String stringResponse = getHtmlContent(url);
Document doc = Jsoup.parse(stringResponse);
Element content = doc.getElementById("content");
//Get all elements with img tag ,
Elements img = content.getElementsByTag("img");
for (Element el : img) {
//for each element get the src image url
String src = el.attr("src");
Log.d(TAG, "src attribute is : " + src);
String alt = el.attr("alt");
//do some stuff
}
Update:
Wikipida provide API for to return HTML Content
I have a math equation as a text WebView that I need to fit the entire screen no matter its dimensions.. my first intuition of doing this is simply shrinking the text whenever it gets out of bounds so that it remains constrained, however, I can't find any functions or methods to actually MEASURE the content of that webview, I've tried:
webview.getMeasuredHeight, webview.getHeight
but the issue with them is that they are constantly affixed on the size of the webview widget, not on the content, so I moved to:
webview.getContentHeight
which seemed to work, the problem is it works only after the text is "loaded", so it doesn't get the right answer at first, even if it's called in onPageFinished.
My questions are:
1) Is there a way to know the content size of the TEXTUAL html webview?? I would even appreciate knowing the scroll bar length that would indicate size.
2) Is there a listener function that would enable me to run code from the moment the text actually loaded? The webview declaration looks something like this:
webView = (WebView) findViewById(R.id.webView);
js = "<html><head>"
+ "<link rel='stylesheet' href='file:///android_asset/mathscribe/jqmath-0.4.3.css'>"
+ "<script src='file:///android_asset/mathscribe/jquery-1.4.3.min.js'></script>"
+ "<script src='file:///android_asset/mathscribe/jqmath-etc-0.4.3.min.js'></script>"
+ "</head><body>"
+ "<script>var s = '$$" + functext + "$$';M.parseMath(s);document.write(s);</script> </body>";
webView.loadDataWithBaseURL("", js, "text/html", "UTF-8", "");
The text does not load instantly, so the code relating to it is usually flawed.
3) Is there a webview.getContentWidth or something of the like?
EDIT:
This code may help you in fitting your wepage to webview.
webview.getSettings().setLoadWithOverviewMode(true);
webview.getSettings().setUseWideViewPort(true);
You have to calculate the scale so that content fits on the screen.
private int getScale()
{
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = display.getWidth();
Double val = new Double(width)/new Double(Your_webpage_width);
val = val * 100d;
return val.intValue();
}
Then use
WebView web = new WebView(this);
web.setPadding(0, 0, 0, 0);
web.setInitialScale(getScale());
2) To run something after webview has completely loaded,just implement WebViewClient and extend onPageFinished() as follows:
mWebView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
// do your stuff here
}
});
I have a cordova (2.7.0) android app that is crashing with an Application Error when it tries to load an iframe where the source has a protocol relative (network-path reference) src.
For instance, if the iframe is:
<iframe src="//instagram.com/p/beGdCuhQYl/embed/?wmode=opaque&wmode=opaque" width="800" height="928" style="border:0;" frameborder="0"></iframe>
Then the app tries to load the source from
file://instagram.com/p/beGdCuhQYl/embed/?wmode=opaque&wmode=opaque
Since the html page that loads this iframe is loaded from the file system, it makes sense that it is doing this. However, is there a way to stop the app from crashing? The same cordova app on iOS just doesn't load anything, and has a blank iframe. I would be nice if the android app behaved the same way.
It would be even nicer if there was a way to tell the cordova app to load these types of urls from http:// and not file:// but I think that is asking too much.
Ok, so I ended up doing this in two parts. First part, try to fix as many protocol relative urls as possible in javascript, and the second part was to provide some java code to ignore any that I missed.
First part (uses jQuery)
/**
* Takes text, looks for elements with src attributes that are
* protocol relative (//) and converts them to http (http://)
* #param {String} text the text that you want to fix urls in
* #returns {String} the updated text with corrected urls
*/
fixProtocolRelativeUrlsInText: function(text) {
var $html, $elements;
try {
$html = $('<div>' + text + '</div>');
$elements = $html.find('[src^="//"]');
if ($elements.length) {
$elements.each(function() {
var $this = $(this);
$this.attr('src', 'http:' + $this.attr('src'));
});
return $html.html();
} else {
return text;
}
} catch(ex) {
return text;
}
},
Second part:
/**
* Override the default makeWebViewClient and provide a custom handler for protocol
* relative urls.
*/
#Override
public CordovaWebViewClient makeWebViewClient(CordovaWebView webView) {
//
// We already try to fix protocol relative urls in the javascript. But this is a safety net in case anything
// gets through. So, in order to not crash the app, lets handle these types ourself and just swallow them up
// for now. The url won't load but at least it won't crash the app either. By the time the protocol relative
// url gets in here, it has the file: appended to it already. If it was a true file:// path to something on the
// device, then it will have file:///some/path, and if it was a protocol relative url that was converted to a
// file:// then it will have file://some.domain, so we look for urls that don't have the three /'s
//
final Pattern pattern = Pattern.compile("^file://[^/].*$");
CordovaWebViewClient webViewClient;
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) {
webViewClient = new CordovaWebViewClient(this, webView) {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Matcher matcher = pattern.matcher(url);
if (matcher.matches()) {
Log.i(LOG_TAG, "swallowing url '" + url + "'");
return true;
} else {
return super.shouldOverrideUrlLoading(view, url);
}
}
};
} else {
webViewClient = new IceCreamCordovaWebViewClient(this, webView) {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Matcher matcher = pattern.matcher(url);
if (matcher.matches()) {
Log.i(LOG_TAG, "swallowing url '" + url + "'");
return true;
} else {
return super.shouldOverrideUrlLoading(view, url);
}
}
};
}
return webViewClient;
}
Cordova doesn't support protocol relative src, it expects you to specify either file, or http.
I am try to show epub book in android pad. I can parse the html and css, in order to show the book's content and format, perhaps the book include pictures, It seems that I have two option:
use Webview.
Write a customer view, so that it can render html/css --- it seems a very complicated task.
Which is the good way? If I have to use WebView, how about the page break logic, since webview parse one html file in one page, I can not find the page break in webview.
I have developed a native epub player for android and ios
Code I shared here is part of my product source code, copying and pasting of it will not work for you. Consider it as reference.
I have used webview in android and uiwebview in ios making custom view and parsing html/css is almost like developing a new rendering engine (i.e browser).Its a tedious and complex.
Briefly I give you the steps I have followed for android
Create a custom webview
load url and write call back clients (WebViewClient,WebChromeClient)
after webview load do pagination using below method
Code:
private class MyWebClient extends WebViewClient
{
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url)
{
super.onPageFinished(view, url);
final MyWebView myWebView = (MyWebView) view;
String varMySheet = "var mySheet = document.styleSheets[0];";
String addCSSRule = "function addCSSRule(selector, newRule) {"
+ "ruleIndex = mySheet.cssRules.length;"
+ "mySheet.insertRule(selector + '{' + newRule + ';}', ruleIndex);"
+ "}";
String insertRule1 = "addCSSRule('html', 'padding: 0px; height: "
+ (myWebView.getMeasuredHeight()/getContext().getResources().getDisplayMetrics().density )
+ "px; -webkit-column-gap: 0px; -webkit-column-width: "
+ myWebView.getMeasuredWidth() + "px;')";
myWebView.loadUrl("javascript:" + varMySheet);
myWebView.loadUrl("javascript:" + addCSSRule);
myWebView.loadUrl("javascript:" + insertRule1);
}
}
private class MyWebChromeClient extends WebChromeClient
{
#Override
public void onProgressChanged(WebView view, int newProgress)
{
super.onProgressChanged(view, newProgress);
// GlobalConstants.ENABLE_WEB_VIEW_TOUCH = false;
if(newProgress == 100)
{
postDelayed(new Runnable()
{
#Override
public void run()
{
calculateNoOfPages();
}
},300);
}
}
}
private void calculateNoOfPages()
{
if(getMeasuredWidth() != 0)
{
int newPageCount = computeHorizontalScrollRange()/getMeasuredWidth();
}
}
Inject jquery.js into webview:
private void addJQueryJS()
{
String path = "file:///android_asset/JSLibraries/jquery.min.js";
String data = "{\"MethodName\":\"onJQueryJSLoaded\",\"MethodArguments\":{}}";
String callBackToNative = " jsInterface.callNativeMethod('jstoobjc:"+data+"');";
String script = "function includeJSFile()"
+"{"
+"function loadScript(url, callback)"
+"{"
+"var script = document.createElement('script');"
+"script.type = 'text/javascript';"
+"script.onload = function () {"
+"callback();"
+"};"
+"script.src = url;"
+"if(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0])"
+"{"
+"(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(script);"
+"}"
+"else { callback(); }"
+"}"
+"loadScript('"+path+"', function ()"
+"{"
+callBackToNative
+"});"
+"} ; includeJSFile();";
loadUrl("javascript: "+script);
}
wrap all words into spans - used for highlighting text and navigating to a page.
there would be 3 webviews - current page ,next page and previous page.You should set offset to webview scroll according to page count of that chapter.
lets say one .html file has content of 3 pages - previous webview is first page,current webview is second page,next webview is third page but all webviews loaded the same url.But their content offset is different.
write you own page swiping logic instead of using viewpager.Just pass the current page to the adapter then adapter will return you the next page and previous page.by some calculations.
Code:
#Override
public PageView getPreviousView(PageView oldPage)
{
MyWebView oldWebView = ((PageView)oldPage).getWebView();
int chapterIndex = oldWebView.getData().getIndexOfChapter();
int pageIndex = oldWebView.getData().getIndexOfPage();
int pageCount = oldWebView.getData().getChapterVO().getPageCount();
pageIndex--;
if(pageIndex < 0)
{
pageIndex = 0;
chapterIndex--;
if(chapterIndex<0)
{
//return the same page
chapterIndex = 0;
return null;
}
else
{
//previous chapter last page
PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
MyWebView webView= pageView.getWebView();
PageVO data = new PageVO();
data.setChapterVO(_chaptersColl.get(chapterIndex));
data.setIndexOfChapter(chapterIndex);
data.setIndexOfPage(-2);
webView.setData(data);
return pageView;
}
}
else if(pageIndex <= pageCount-1)
{
//same chapter previous page
PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
MyWebView webView= pageView.getWebView();
PageVO data = new PageVO();
data.setChapterVO(_chaptersColl.get(chapterIndex));
data.setIndexOfChapter(chapterIndex);
data.setIndexOfPage(pageIndex);
webView.setData(data);
return pageView;
}
return oldPage;
}
#Override
public PageView getNextView(PageView oldPage)
{
MyWebView oldWebView = ((PageView)oldPage).getWebView();
int chapterIndex = oldWebView.getData().getIndexOfChapter();
int pageIndex = oldWebView.getData().getIndexOfPage();
int pageCount = oldWebView.getData().getChapterVO().getPageCount();
pageIndex++;
if(pageIndex>=pageCount)
{
pageIndex=0;
chapterIndex++;
if(chapterIndex>=_chaptersColl.size())
{
//end of the chapters and pages so return the same page
chapterIndex--;
return null;
}
else
{
//next chapter first page
PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
MyWebView webView= pageView.getWebView();
PageVO data = new PageVO();
data.setChapterVO(_chaptersColl.get(chapterIndex));
data.setIndexOfChapter(chapterIndex);
data.setIndexOfPage(pageIndex);
webView.setData(data);
return pageView;
}
}
else
{
//next page in same chapter
PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
MyWebView webView= pageView.getWebView();
PageVO data = new PageVO();
data.setChapterVO(_chaptersColl.get(chapterIndex));
data.setIndexOfChapter(chapterIndex);
data.setIndexOfPage(pageIndex);
//data.setPageCount(pageCount);
webView.setData(data);
return pageView;
}
}
No need to use any third party libs .Just need to spend good amount of time to write every thing your own.
Nice One, But in Question... :-)
I don't think any Page Break logic for android webview is available, As per your concern WebView is the good choice to display .epub file (You can add many functionality like, highlight, search, bookmark etc..). And If you found that one then what about if device size is changed. What I am doing is, I just display WebPage in webview and disable scroll, Then I can find the max height of webview, and device screen size (Height and width), Now I have put two buttons for next and previous pages, which just scroll page according to height of device size..
Something easy.. Try this if you want to... (This is my personal opinion may be I am wrong on this)
There's this javascript library that takes care of the pagination issue
http://monocle.inventivelabs.com.au/
This project uses it in android
https://github.com/sharathpuranik/chaek-android
Grab the sourcecode and take a look.
In some web browsers, huge images are automatically resized to fit the screen.
Is it possible to do the same in an Android WebView?
The web page just contains the image, maybe adding some JavaScript could do the trick?
Anybody has already done this?
Note: I don't know the size of the image in advance.
Yes, it's possible. You can try setting the WebView Layout using the code below. It resizes all Images (Greater than the Device Screen Width) to the Screen Width. This works for both Orientations (Portrait and Landscape)
webview.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
You can add extra margins/padding later to get the spacing right.
webview.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
works but is deprecated. This is another solution without LayoutAlgorithm.SINGLE_COLUMN, using CSS:
#SuppressLint("NewApi")
private openWebView() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.TEXT_AUTOSIZING);
} else {
webView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
}
String data = "<div> your HTML content </div>";
webView.loadDataWithBaseURL("file:///android_asset/", getHtmlData(data), "text/html", "utf-8", null);
}
private String getHtmlData(String bodyHTML) {
String head = "<head><style>img{max-width: 100%; width:auto; height: auto;}</style></head>";
return "<html>" + head + "<body>" + bodyHTML + "</body></html>";
}
You could use this:
WebView webView = (WebView) findViewById(R.id.myWebView);
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setUseWideViewPort(true);
Found this solution here:
How to set the initial zoom/width for a webview
You can have the browser resize the image for you to fit the maximum width of the screen:
<img src="huge-image.jpg" width="100%" />
Resizing its height to WebView's viewport is possible too:
<img src="huge-image.jpg" height="100%" />
However, resizing both width and height would result in a stretched image. To either resize the width or height depending of what side fits best you may consider a bit of JavaScript, like this:
<img src="huge-image.jpg" onload="resize(this);" />
<script type="text/javascript">
function resize(image)
{
var differenceHeight = document.body.clientHeight - image.clientHeight;
var differenceWidth = document.body.clientWidth - image.clientWidth;
if (differenceHeight < 0) differenceHeight = differenceHeight * -1;
if (differenceWidth < 0) differenceWidth = differenceWidth * -1;
if (differenceHeight > differenceWidth)
{
image.style['height'] = document.body.clientHeight + 'px';
}
else
{
image.style['width'] = document.body.clientWidth + 'px';
}
// Optional: remove margins or compensate for offset.
image.style['margin'] = 0;
document.body.style['margin'] = 0;
}
</script>
I faced the same problem and used Jsoup to help me out and add the required respected CSS. You can easily add attributes or CSS. I my case, I download from many sources various different HTML files, save them and then display them in a Webview. Here is how I parse the HTML before I save it to the database with Kotlin:
// Parse your HTML file or String with Jsoup
val doc = Jsoup.parse("<html>MY HTML STRING</html>")
// doc.select selects all tags in the the HTML document
doc.select("img").attr("width", "100%") // find all images and set with to 100%
doc.select("figure").attr("style", "width: 80%") // find all figures and set with to 80%
doc.select("iframe").attr("style", "width: 100%") // find all iframes and set with to 100%
// add more attributes or CSS to other HTML tags
val updatedHTMLString = doc.html()
// save to database or load it in your WebView
Add Jsoup to your project
Have fun!
If your WebView width is fill_parent then you can use this code:
Display display=getWindowManager().getDefaultDisplay();
int width=display.getWidth();
String data="<img src='http://example.com/image.jpg' style='width:"+width+"px' />";
webView.loadData(data, "text/html", "utf-8");
And zoom still working!
Same method if height is fill_parent.
My favorite's :
String data = "<html><body ><img id=\"resizeImage\" src=\""+PictureURL+"\" width=\"100%\" alt=\"\" align=\"middle\" /></body></html>";
webview.loadData(data, "text/html; charset=UTF-8", null);
You could send the size you want in the request parameters and let the server set the width/height in the img element for you.