I'm looki开发者_JAVA技巧ng for a way to detect whether or not a WebView is zoomed out fully. I know you can get a boolean return value from ZoomOut(), but that will perform the zoom out. I just want to simply know whether or not it can.
I use my custom WebView
class.
Get WebView
's view height and inner html web page's contentHeight
.
Calculate defaultScale = WebView.getHeight() / WebView.getContentHeight();
and currentScale = WebView.getScale()
.
If defaultScale
< currentScale
it's zoomed.
public class NoZoomControllWebView extends WebView {
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@SuppressWarnings("deprecation")
public boolean isZoomed () {
boolean result = false;
int contentHeight = getContentHeight();
int viewHeight = getHeight();
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR1 ) {
float scale = getScale();
int temp = (int)(((float)viewHeight / (float)contentHeight) * 100);
if (temp < (int)(scale * 100)) {
result = true;
}
} else {
float scale = getScale();
int temp = (int)(((float)viewHeight / (float)contentHeight) * 100);
if (temp < (int)(scale * 100)) {
result = true;
}
}
return result;
}
}
getScaled()
is deprecated you should use onScaleChanged
on your WebViewClient instead
You can use it like this:
private boolean zoomed = false, firstRun = true;
@Override
public void onScaleChanged(WebView view, float oldScale,
float newScale) {
if (firstRun) {
initScale = newScale;
firstRun=false;
zoomed = false;
}
else {
if (newScale>oldScale) {
zoomed = true;
}
else {
if (newScale<initScale) {
zoomed = false;
}
}
}
super.onScaleChanged(view, oldScale, newScale);
}
if we presume the WebView is zoomed max out from the start.
Create your own class which extends WebView and override the zoomOut() method. Every time the user zooms out, call super.zoomOut(). Save what is returned to a boolean variable with class scope so it can be persisted with onSaveInstanceState() or in SharedPreferences if needed.
public class MyWebView extends WebView {
// WebViews are generally zoomed out all the way when first created so set defaults
private boolean lastZoomInResult = true;
private boolean lastZoomOutResult = false;
@Override
public boolean zoomIn() {
lastZoomInResult = super.zoomIn();
return lastZoomInResult;
}
@Override
public boolean zoomOut() {
lastZoomOutResult = super.zoomOut();
return lastZoomOutResult;
}
EDIT: In response to this not working for pinch zoom... you are quite correct and ultimately Cristian's answer holds true.
I hooked my phone up via USB to my PC with DDMS. I see the following when I pinch zoom my Webview...
01-06 03:18:19.052: DEBUG/SurfaceFlinger(92): Layer::setBuffers(this=0x849ac0), pid=23072, w=1, h=1
01-06 03:18:19.052: DEBUG/SurfaceFlinger(92): Layer::setBuffers(this=0x849ac0), pid=23072, w=1, h=1
01-06 03:18:19.082: DEBUG/SurfaceFlinger(92): Layer::requestBuffer(this=0x849ac0), index=0, pid=23072, w=480, h=74 success
01-06 03:18:19.832: DEBUG/SurfaceFlinger(92): Layer::setBuffers(this=0x738378), pid=23072, w=1, h=1
01-06 03:18:19.832: DEBUG/SurfaceFlinger(92): Layer::setBuffers(this=0x738378), pid=23072, w=1, h=1
01-06 03:18:19.852: DEBUG/SurfaceFlinger(92): Layer::requestBuffer(this=0x738378), index=0, pid=23072, w=480, h=74 success
In short, it isn't WebView which is zooming. What's actually happening is a digital zoom of the graphics display - the WebView content stays exactly the same size regardless of a zoom in or out but it's being digitally 'magnified' or 'shrunk' like the digital zoom on a digital camera.
I don't fully understand what SurfaceFlinger is but from a quick Google search, we're talking 'device driver' stuff here.
The only thing that changes in those SurfaceFlinger log messages are the hex value for 'this=' and they bear no relevance to the zoom state. The above is logging two pinch attempts when the screen was fully zoomed out.
I'm curious to see what else anyone might come up with but I was able to accomplish this through javascript. It's frustrating because I can see the values needed to easily determine this in the source code of the WebView but they are private with no getters...
Anyhow the solution I have so far is add a JavaScriptInterface which allows me to get the document.body.scrollWidth value for the page. This provides me with the scrollable width, which for some reason is not available even though there is a getContentHeight() method. Using this, I can calculate whether or not it is fully zoomed out.
Here is the method the javascript interface calls:
public void checkIfZoomedOut(int scrollWidth){
int zoomedOutThreshold = 5; // If you want to include "nearly zoomed out"
if( Math.abs(Math.ceil(mWebView.getScale() * scrollWidth) - mWebView.getWidth()) <= zoomedOutThreshold){
// It is zoomed out
} else {
// It is zoomed in
}
}
The scrollWidth is document.body.scrollWidth
Edit: After further experimenting I found protected methods called computeHorizontalScrollRange() and computeHorizontalScrollExtent() that can be called if you subclass the WebView. You can use them to determine if horizontal scrolling is active/needed. However, some webpages can be fully zoomed out (the WebView won't let you zoom out any further) and still have a horizontal scrollbar, such as webpages with text. So it's not perfect.
if( !webView.zoomOut () ){
// couldn't zoom out because the zoom out did nothing :(
// THIS IS WHAT YOU WANT TO KNOW!
} else{
webView.zoomIn(); // restore
}
I just want to simply know whether or not it can.
There's no way to do so.
精彩评论