enable/disable zoom in Android WebView
Asked Answered
C

8

66

There are some methods in WebSettings related to zoom:

  • WebSettings.setSupportZoom
  • WebSettings.setBuiltInZoomControls

I noticed they work differently on some devices. For example, on my Galaxy S pinch to zoom is enabled by default, but on LG P500 it is disabled (And now I don't know how to enable ONLY pinch to zoom, but hide zooming buttons).

On P500 when I call setBuiltInZoomControls(true) I get both these variants working (multitouch and buttons).

How to enable multitouch zoom and disable zooming buttons on devices such an LG P500? (Also, I know the same problems are on HTC devices)

UPDATE: Here is almost full code for the solution

if (ev.getAction() == MotionEvent.ACTION_DOWN ||
        ev.getAction() == MotionEvent.ACTION_POINTER_DOWN ||
        ev.getAction() == MotionEvent.ACTION_POINTER_1_DOWN ||
        ev.getAction() == MotionEvent.ACTION_POINTER_2_DOWN ||
        ev.getAction() == MotionEvent.ACTION_POINTER_3_DOWN) {
    if (multiTouchZoom && !buttonsZoom) {
        if (getPointerCount(ev) > 1) {
            getSettings().setBuiltInZoomControls(true);
            getSettings().setSupportZoom(true);
        } else {
            getSettings().setBuiltInZoomControls(false);
            getSettings().setSupportZoom(false);
        }
    }
}

if (!multiTouchZoom && buttonsZoom) {
    if (getPointerCount(ev) > 1) {
        return true;
    }
}

This code is in my onTouchEvent overridden method of the WebView.

Chari answered 26/2, 2011 at 8:23 Comment(4)
I've got the same problem.. what are the multiTouchZoom and the buttonsZoom variable?Cowage
@Luizje I know this is old, but in case anybody else finds it: Change getPointerCount(ev) to ev.getPointerCount() and it will work!Kostival
I'm not sure if anybody needs this anymore, but have a look at my "hack around". It works back to Android 1.6Filippa
@Evgeny What are the multiTouchZoom and the buttonsZoom variable? How did you get events for zoom buttons and multitouchZoom? if you don't mind, Can you please post full code here ?Rettarettig
S
37

I've looked at the source code for WebView and I concluded that there is no elegant way to accomplish what you are asking.

What I ended up doing was subclassing WebView and overriding OnTouchEvent. In OnTouchEvent for ACTION_DOWN, I check how many pointers there are using MotionEvent.getPointerCount(). If there is more than one pointer, I call setSupportZoom(true), otherwise I call setSupportZoom(false). I then call the super.OnTouchEvent().

This will effectively disable zooming when scrolling (thus disabling the zoom controls) and enable zooming when the user is about to pinch zoom. Not a nice way of doing it, but it has worked well for me so far.

Note that getPointerCount() was introduced in 2.1 so you'll have to do some extra stuff if you support 1.6.

Sherlynsherm answered 17/3, 2011 at 23:53 Comment(2)
Thanks for that solution. It works almost the way I want. I'll post summary of code in the questionChari
Did I say I love you, gngr44?Fulsome
T
117

On API >= 11, you can use:

wv.getSettings().setBuiltInZoomControls(true);
wv.getSettings().setDisplayZoomControls(false);

As per the SDK:

public void setDisplayZoomControls (boolean enabled) 

Since: API Level 11

Sets whether the on screen zoom buttons are used. A combination of built in zoom controls enabled and on screen zoom controls disabled allows for pinch to zoom to work without the on screen controls

Transmigrate answered 26/10, 2011 at 13:27 Comment(3)
Too bad 60%+ of users are still using pre-API 11... and I'm saying this a year after you posted it! What'd the numbers look like when you posted the suggestion?Lucila
I used this with this answer to default my view to zoomed out and to be able to pinch-to-zoom. I just left off the display part to work with pre-API 11Adaptive
Good answer. Also make sure that another controlling factor is "user-scalable" in the meta <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">Hypogeum
S
37

I've looked at the source code for WebView and I concluded that there is no elegant way to accomplish what you are asking.

What I ended up doing was subclassing WebView and overriding OnTouchEvent. In OnTouchEvent for ACTION_DOWN, I check how many pointers there are using MotionEvent.getPointerCount(). If there is more than one pointer, I call setSupportZoom(true), otherwise I call setSupportZoom(false). I then call the super.OnTouchEvent().

This will effectively disable zooming when scrolling (thus disabling the zoom controls) and enable zooming when the user is about to pinch zoom. Not a nice way of doing it, but it has worked well for me so far.

Note that getPointerCount() was introduced in 2.1 so you'll have to do some extra stuff if you support 1.6.

Sherlynsherm answered 17/3, 2011 at 23:53 Comment(2)
Thanks for that solution. It works almost the way I want. I'll post summary of code in the questionChari
Did I say I love you, gngr44?Fulsome
F
29

We had the same problem while working on an Android application for a customer and I managed to "hack" around this restriction.

I took a look at the Android Source code for the WebView class and spotted a updateZoomButtonsEnabled()-method which was working with an ZoomButtonsController-object to enable and disable the zoom controls depending on the current scale of the browser.

I searched for a method to return the ZoomButtonsController-instance and found the getZoomButtonsController()-method, that returned this very instance.

Although the method is declared public, it is not documented in the WebView-documentation and Eclipse couldn't find it either. So, I tried some reflection on that and created my own WebView-subclass to override the onTouchEvent()-method, which triggered the controls.

public class NoZoomControllWebView extends WebView {

    private ZoomButtonsController zoom_controll = null;

    public NoZoomControllWebView(Context context) {
        super(context);
        disableControls();
    }

    public NoZoomControllWebView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        disableControls();
    }

    public NoZoomControllWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        disableControls();
    }

    /**
     * Disable the controls
     */
    private void disableControls(){
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
            // Use the API 11+ calls to disable the controls
            this.getSettings().setBuiltInZoomControls(true);
            this.getSettings().setDisplayZoomControls(false);
        } else {
            // Use the reflection magic to make it work on earlier APIs
            getControlls();
        }
    }

    /**
     * This is where the magic happens :D
     */
    private void getControlls() {
        try {
            Class webview = Class.forName("android.webkit.WebView");
            Method method = webview.getMethod("getZoomButtonsController");
            zoom_controll = (ZoomButtonsController) method.invoke(this, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        super.onTouchEvent(ev);
        if (zoom_controll != null){
            // Hide the controlls AFTER they where made visible by the default implementation.
            zoom_controll.setVisible(false);
        }
        return true;
    }
}

You might want to remove the unnecessary constructors and react on probably on the exceptions.

Although this looks hacky and unreliable, it works back to API Level 4 (Android 1.6).


As @jayellos pointed out in the comments, the private getZoomButtonsController()-method is no longer existing on Android 4.0.4 and later.

However, it doesn't need to. Using conditional execution, we can check if we're on a device with API Level 11+ and use the exposed functionality (see @Yuttadhammo answer) to hide the controls.

I updated the example code above to do exactly that.

Filippa answered 10/8, 2012 at 12:45 Comment(5)
@Lukas, it won't work on Android 4.0.4. It returns NoSuchMethodException: getZoomButtonsController.Garb
@Garb On Android 4 you can use the WebSettings.setDisplayZoomControls(boolean) method which is available from API Level 11.Filippa
@LukasKnuth thank you for your help. Now it works. I change my target Api level to 11+. As said at conditional execution. Before my target Api is 10 so I can't use the .setDisplayZoomControls(boolean) function. Again, thanks you.Garb
if anyone is having trouble getting zooming to work on pre-API 11 devices, move the this.getSettings().setBuiltInZoomControls(true); to run on all WebViews, not just the API 11 or higher ones. (still hides the zoom controls. I also added this.getSettings().setUseWideViewPort(true); for double-tap zoomForemost
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { Use this if you have min sdk version is 2.3.3 (API level 10)Gilletta
A
10

Ive modifiet Lukas Knuth's solution a little:

1) There's no need to subclass the webview,

2) the code will crash during bytecode verification on some Android 1.6 devices if you don't put nonexistant methods in seperate classes

3) Zoom controls will still appear if the user scrolls up/down a page. I simply set the zoom controller container to visibility GONE

  wv.getSettings().setSupportZoom(true);
  wv.getSettings().setBuiltInZoomControls(true);
  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
    // Use the API 11+ calls to disable the controls
    // Use a seperate class to obtain 1.6 compatibility
    new Runnable() {
      public void run() {
        wv.getSettings().setDisplayZoomControls(false);
      }
    }.run();
  } else {
    final ZoomButtonsController zoom_controll =
        (ZoomButtonsController) wv.getClass().getMethod("getZoomButtonsController").invoke(wv, null);
    zoom_controll.getContainer().setVisibility(View.GONE);
  }
Anemoscope answered 7/2, 2013 at 12:58 Comment(4)
Perfect solution. Only thing I'd change is invoke(webview, (Object[]) null)) so you don't get an warning in Eclipse.Maestro
Looks like a good solution. I cannot compile because of this error: Call requires API level 11 (current min is 8): android.webkit.WebSettings#setDisplayZoomControlsAlejandro
Press Ctrl-1 for @SuppressLintAlejandro
@Alejandro This method only hide zoom controls but don't disable those buttons (On API level 10,In webview if I touch right bottom then it gets zoomin-out).Is there any solution to resolve that problem? Above API 10 it works.Pentarchy
H
7

Lukas Knuth have good solution, but on android 4.0.4 on Samsung Galaxy SII I still look zoom controls. And I solve it via

if (zoom_controll!=null && zoom_controll.getZoomControls()!=null)
{
   // Hide the controlls AFTER they where made visible by the default implementation.
   zoom_controll.getZoomControls().setVisibility(View.GONE);
}

instead of

if (zoom_controll != null){
   // Hide the controlls AFTER they where made visible by the default implementation.
   zoom_controll.setVisible(false);
}
Hartford answered 16/10, 2012 at 8:6 Comment(1)
I know this answer is several months old, but I just wanted to say thanks. This answer in combination with Lukas Knuth's is perfect.Scrutineer
A
1

The solution you posted seems to work in stopping the zoom controls from appearing when the user drags, however there are situations where a user will pinch zoom and the zoom controls will appear. I've noticed that there are 2 ways that the webview will accept pinch zooming, and only one of them causes the zoom controls to appear despite your code:

User Pinch Zooms and controls appear:

ACTION_DOWN
getSettings().setBuiltInZoomControls(false); getSettings().setSupportZoom(false);
ACTION_POINTER_2_DOWN
getSettings().setBuiltInZoomControls(true); getSettings().setSupportZoom(true);
ACTION_MOVE (Repeat several times, as the user moves their fingers)
ACTION_POINTER_2_UP
ACTION_UP

User Pinch Zoom and Controls don't appear:

ACTION_DOWN
getSettings().setBuiltInZoomControls(false); getSettings().setSupportZoom(false);
ACTION_POINTER_2_DOWN
getSettings().setBuiltInZoomControls(true); getSettings().setSupportZoom(true);
ACTION_MOVE (Repeat several times, as the user moves their fingers)
ACTION_POINTER_1_UP
ACTION_POINTER_UP
ACTION_UP

Can you shed more light on your solution?

Astra answered 6/7, 2011 at 22:38 Comment(0)
H
1

Improved Lukas Knuth's version:

public class TweakedWebView extends WebView {

    private ZoomButtonsController zoomButtons;

    public TweakedWebView(Context context) {
        super(context);
        init();
    }

    public TweakedWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public TweakedWebView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        getSettings().setBuiltInZoomControls(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            getSettings().setDisplayZoomControls(false);
        } else {
            try {
                Method method = getClass()
                        .getMethod("getZoomButtonsController");
                zoomButtons = (ZoomButtonsController) method.invoke(this);
            } catch (Exception e) {
                // pass
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean result = super.onTouchEvent(ev);
        if (zoomButtons != null) {
            zoomButtons.setVisible(false);
            zoomButtons.getZoomControls().setVisibility(View.GONE);
        }
        return result;
    }

}
Hidden answered 4/5, 2013 at 19:0 Comment(0)
C
1

hey there for anyone who might be looking for solution like this.. i had issue with scaling inside WebView so best way to do is in your java.class where you set all for webView put this two line of code: (webViewSearch is name of my webView -->webViewSearch = (WebView) findViewById(R.id.id_webview_search);)

// force WebView to show content not zoomed---------------------------------------------------------
    webViewSearch.getSettings().setLoadWithOverviewMode(true);
    webViewSearch.getSettings().setUseWideViewPort(true);
Comparable answered 6/12, 2016 at 15:19 Comment(3)
is this like desktop mode?Roundelay
hm, since webView is the view that shows web pages, and those two by definition are: setLoadWithOverviewMode(boolean overview) Sets whether the WebView loads pages in overview mode, that is, zooms out the content to fit on screen by width, and setUseWideViewPort(boolean use) Sets whether the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. You can say that is like destkop mode ^^Comparable
I just wonder how third party web browsers switch the "desktop mode". I don't think they use this. I think they change the user agent or something.Roundelay

© 2022 - 2024 — McMap. All rights reserved.