Включить/отключить масштабирование в Android WebView

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

Этот код находится в моем onTouchEvent переопределенном методе WebView.

Ответ 1

Я посмотрел исходный код для WebView, и я пришел к выводу, что нет элегантного способа выполнить то, что вы просите.

То, что я закончил, было подклассификация WebView и переопределение OnTouchEvent. В OnTouchEvent для ACTION_DOWN, я проверяю, сколько указателей там используется MotionEvent.getPointerCount(). Если имеется более одного указателя, я вызываю setSupportZoom(true), иначе я вызываю setSupportZoom(false). Затем я вызываю super.OnTouchEvent().

Это приведет к эффективному отключению масштабирования при прокрутке (таким образом отключив элементы управления масштабированием) и включив масштабирование, когда пользователь собирается зажать масштаб. Не очень хороший способ сделать это, но он до сих пор хорошо работал у меня.

Обратите внимание, что getPointerCount() был введен в 2.1, поэтому вам придется делать некоторые дополнительные вещи, если вы поддерживаете 1.6.

Ответ 2

В API >= 11 вы можете использовать:

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

В соответствии с SDK:

public void setDisplayZoomControls (boolean enabled) 

С: Уровень API 11

Устанавливает, используются ли кнопки масштабирования на экране. Сочетание встроенные средства управления масштабированием включены, а кнопки управления масштабированием экрана отключены позволяет щепотку масштабировать для работы без элементов управления на экране.

Ответ 3

У нас была та же проблема, когда мы работали над Android-приложением для клиента, и мне удалось "взломать" это ограничение.

Я взглянул на исходный код Android для класса WebView и заметил updateZoomButtonsEnabled() -method, который работал с ZoomButtonsController -object, чтобы включить или отключить элементы управления масштабированием в зависимости от текущего масштаба браузера.

Я искал метод возврата ZoomButtonsController -instance и нашел getZoomButtonsController() -method, который вернул этот самый экземпляр.

Хотя метод объявлен public, он не документирован в WebView -документации, и Eclipse тоже не смог его найти. Итак, я пробовал некоторое размышление над этим и создал свой собственный WebView -subclass, чтобы переопределить метод 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), чтобы скрыть элементы управления.

Я обновил приведенный выше код примера, чтобы сделать именно это.

Ответ 4

Я немного изменил решение Лукаса Кнута:

1) Нет необходимости подклассифицировать веб-просмотр,

2) код будет сбой во время проверки байт-кода на некоторых устройствах Android 1.6, если вы не ставите нестерильные методы в отдельные классы

3) Элементы управления масштабированием по-прежнему будут отображаться, если пользователь прокручивает страницу вверх/вниз. Я просто установил контейнер контроллера масштабирования в режим видимости 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);
  }

Ответ 5

У Лукаса Кнута есть хорошее решение, но на Android 4.0.4 на Samsung Galaxy SII я все еще смотрю зум-контроль. И я решаю его через

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

Ответ 6

Решение, которое вы опубликовали, похоже, работает с тем, чтобы остановить элементы управления масштабированием, появляющиеся при перетаскивании пользователя, однако есть ситуации, когда пользователь будет зажимать масштаб, и появятся кнопки управления увеличением. Я заметил, что есть два способа, по которым веб-просмотр будет принимать масштабирование, и только один из них приводит к появлению элементов управления увеличением, несмотря на ваш код:

Появятся пользовательские кнопки и элементы управления:

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

Можете ли вы пролить свет на свое решение?

Ответ 7

Улучшена версия Лукаса Кнута:

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

}

Ответ 8

Эй, для тех, кто может искать такое решение.. У меня проблема с масштабированием внутри 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);