在 Android WebView 中启用/禁用缩放

发布于 2024-10-19 02:46:06 字数 1246 浏览 2 评论 0原文

WebSettings 中有一些与缩放相关的方法:

  • WebSettings.setSupportZoom
  • WebSettings.setBuiltInZoomControls

我注意到它们在某些设备上的工作方式有所不同。 例如,在我的 Galaxy S 上,默认情况下启用捏合缩放,但在 LG P500 上它被禁用(现在我不知道如何启用“仅捏合缩放”,但隐藏缩放按钮)。

在 P500 上,当我调用 setBuiltInZoomControls(true) 时,这两种变体都可以工作(多点触控和按钮)。

如何在 LG P500 等设备上启用多点触控缩放并禁用缩放按钮? (另外,我知道 HTC 设备上也存在同样的问题)

更新:这里是解决方案的几乎完整代码

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;
    }
}

此代码位于我的 WebView 的 onTouchEvent 重写方法中。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

怎樣才叫好 2024-10-26 02:46:06

在 API >= 11 上,您可以使用:

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

根据 SDK:

public void setDisplayZoomControls (boolean enabled) 

自:API 级别
11

设置是否使用屏幕缩放按钮。的组合
启用内置缩放控件并禁用屏幕缩放控件
允许在没有屏幕控制的情况下进行捏合缩放操作

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

罗罗贝儿 2024-10-26 02:46:06

我查看了 WebView 的源代码,得出的结论是没有优雅的方法来完成您所要求的任务。

我最终所做的是子类化 WebView 并重写 OnTouchEvent
ACTION_DOWNOnTouchEvent 中,我使用 MotionEvent.getPointerCount() 检查有多少个指针。
如果有多个指针,我会调用 setSupportZoom(true),否则我会调用 setSupportZoom(false)。然后,我调用 super.OnTouchEvent()。

这将有效地在滚动时禁用缩放(从而禁用缩放控件),并在用户即将捏缩放时启用缩放。这不是一个很好的方法,但到目前为止对我来说效果很好。

请注意,getPointerCount() 是在 2.1 中引入的,因此如果您支持 1.6,则必须执行一些额外的操作。

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.

墨落成白 2024-10-26 02:46:06

我们在为客户开发 Android 应用程序时遇到了同样的问题,我设法“破解”了这个限制。

我查看了 WebView 类的 Android 源代码,发现了 updateZoomButtonsEnabled()-method 正在使用 ZoomButtonsController-object 用于启用和禁用缩放控件,具体取决于浏览器的当前比例。

我搜索了返回 ZoomButtonsController 实例的方法,并找到了 getZoomButtonsController()-method,返回了这个非常实例。

尽管该方法被声明为 public,但它没有记录在 WebView 文档中,Eclipse 也找不到它。因此,我尝试对此进行一些反思,并创建了自己的 WebView 子类来重写触发控件的 onTouchEvent() 方法。

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;
    }
}

您可能想要删除不必要的构造函数并可能对异常做出反应。

虽然这看起来很老套且不可靠,但它可以返回到 API 级别 4 (Android 1.6)。


正如 @jayellos 在评论中指出的那样,私有 getZoomButtonsController()-Android 4.0.4 及更高版本中不再存在该方法。

然而,它并不需要这样做。使用条件执行,我们可以检查我们是否在设备上API 级别 11+ 并使用公开的功能(请参阅 @Yuttadhammo 答案)来隐藏控件。

我更新了上面的示例代码来做到这一点。

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.

公布 2024-10-26 02:46:06

我对 Lukas Knuth 的解决方案进行了一些修改:

1)无需对 webview 进行子类化,

2)如果您不将不存在的方法放入单独的类中,则在某些 Android 1.6 设备上的字节码验证期间代码将崩溃

3)缩放控件仍然会出现如果用户向上/向下滚动页面。我只是将缩放控制器容器设置为可见性消失

  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);
  }

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);
  }
一萌ing 2024-10-26 02:46:06

Lukas Knuth 有很好的解决方案,但在 Samsung Galaxy SII 上的 android 4.0.4 上我仍然关注缩放控件。我通过

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);
}

而不是解决它

if (zoom_controll != null){
   // Hide the controlls AFTER they where made visible by the default implementation.
   zoom_controll.setVisible(false);
}

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);
}
别念他 2024-10-26 02:46:06

您发布的解决方案似乎可以阻止用户拖动时出现缩放控件,但是在某些情况下,用户会捏缩放并且会出现缩放控件。我注意到,网络视图有两种方式接受捏缩放,并且只有其中一种会导致缩放控件出现,尽管您的代码:

用户捏缩放和控件出现:

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

用户捏缩放和控件不出现:

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

可以你对你的解决方案有更多的了解吗?

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?

℉絮湮 2024-10-26 02:46:06

改进了 Lukas Knuth 的版本:

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;
    }

}

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;
    }

}
压抑⊿情绪 2024-10-26 02:46:06

嘿,对于任何可能正在寻找这样的解决方案的人来说..我在 WebView 内部缩放时遇到了问题,所以最好的方法是在 java.class 中为 webView 设置所有内容,放入这两行代码:(webViewSearch 的名称我的 webView -->webViewSearch = (WebView) findViewById(R.id.id_webview_search);)

// force WebView to show content not zoomed---------------------------------------------------------
    webViewSearch.getSettings().setLoadWithOverviewMode(true);
    webViewSearch.getSettings().setUseWideViewPort(true);

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文