65

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.

Rakesh
  • 2,946
  • 2
  • 14
  • 28
Evgeny Nacu
  • 1,573
  • 2
  • 12
  • 20
  • 7
    I've got the same problem.. what are the multiTouchZoom and the buttonsZoom variable? – Luciano Mar 21 '12 at 12:15
  • 1
    @Luizje I know this is old, but in case anybody else finds it: Change getPointerCount(ev) to ev.getPointerCount() and it will work! – Shane Grant Jun 07 '12 at 20:39
  • 1
    I'm not sure if anybody needs this anymore, but have a look at my "hack around". It works back to Android 1.6 – Lukas Knuth Aug 10 '12 at 12:45
  • @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 ? – Mallikarjun Nov 08 '13 at 06:47

8 Answers8

116

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

yuttadhammo
  • 4,879
  • 6
  • 32
  • 44
  • 10
    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? – ArtOfWarfare Sep 18 '12 at 13:02
  • I used this with [this answer](http://stackoverflow.com/a/13543216/536986) 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 11 – Cameron Sep 26 '13 at 22:42
  • Good answer. Also make sure that another controlling factor is "user-scalable" in the meta – Tejasvi Hegde Feb 23 '15 at 14:03
36

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.

Nibha Jain
  • 6,032
  • 10
  • 40
  • 63
gngr44
  • 1,348
  • 9
  • 10
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.

yanchenko
  • 53,981
  • 33
  • 142
  • 163
Lukas Knuth
  • 24,328
  • 14
  • 80
  • 107
  • @Lukas, it won't work on Android 4.0.4. It returns NoSuchMethodException: getZoomButtonsController. – jayellos Sep 12 '12 at 05:40
  • 1
    @jayellos On Android 4 you can use the [`WebSettings.setDisplayZoomControls(boolean)`](http://developer.android.com/reference/android/webkit/WebSettings.html#setDisplayZoomControls%28boolean%29) method which is available from API Level 11. – Lukas Knuth Sep 12 '12 at 14:02
  • @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. – jayellos Sep 13 '12 at 02:33
  • 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 zoom – Glenn.nz Oct 28 '12 at 21:47
  • 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) – binary Jun 30 '14 at 18:58
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);
  }
Jacob Nordfalk
  • 3,373
  • 18
  • 21
  • Perfect solution. Only thing I'd change is invoke(webview, (Object[]) null)) so you don't get an warning in Eclipse. – twig Sep 08 '13 at 23:10
  • Looks like a good solution. I cannot compile because of this error: Call requires API level 11 (current min is 8): android.webkit.WebSettings#setDisplayZoomControls – ropo Dec 05 '13 at 12:25
  • Press Ctrl-1 for @SuppressLint – ropo Dec 05 '13 at 12:32
  • @ropo 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. – Giru Bhai Aug 28 '14 at 13:14
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);
}
gnat
  • 6,199
  • 101
  • 49
  • 71
Mihail M
  • 71
  • 1
  • 2
  • 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. – anthonycr Jun 28 '13 at 16:43
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;
    }

}
yanchenko
  • 53,981
  • 33
  • 142
  • 163
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?

WarrenFaith
  • 56,228
  • 24
  • 130
  • 145
Pete
  • 3,722
  • 2
  • 29
  • 42
0

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);
Perhpethua
  • 81
  • 1
  • 1
  • 7
  • is this like desktop mode? – android developer Mar 21 '17 at 15:13
  • 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 ^^ – Perhpethua Mar 23 '17 at 12:23
  • 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. – android developer Mar 23 '17 at 15:57