66 votes

activer/désactiver le zoom dans Android WebView

Il y a quelques méthodes dans WebSettings liées au zoom :

  • Paramètres Web.setSupportZoom
  • WebSettings.setBuiltInZoomControls (Réglages Web)

J'ai remarqué qu'ils fonctionnent différemment sur certains appareils. Par exemple, sur mon Galaxy S, le pincement pour zoomer est activé par défaut, mais sur le LG P500, il est désactivé (et maintenant je ne sais pas comment activer SEULEMENT le pincement pour zoomer, mais cacher les boutons de zoom).

Sur P500 quand j'appelle setBuiltInZoomControls(true) J'ai réussi à faire fonctionner ces deux variantes (multitouch et boutons).

Comment activer le zoom multitouch et désactiver les boutons de zoom sur des appareils tels que le LG P500 (je sais aussi que les mêmes problèmes se posent sur les appareils HTC) ?

UPDATE : Voici le code presque complet de la 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;
    }
}

Ce code est dans mon onTouchEvent méthode surchargée du WebView.

7 votes

J'ai le même problème à quoi servent les variables multiTouchZoom et buttonsZoom ?

1 votes

@Luizje Je sais que c'est vieux, mais au cas où quelqu'un d'autre le trouverait : Changez getPointerCount(ev) en ev.getPointerCount() et ça marchera !

1 votes

Je ne suis pas sûr que quelqu'un en ait encore besoin, mais jetez un coup d'oeil à mon "hack around". Il fonctionne jusqu'à Android 1.6

117voto

yuttadhammo Points 1562

Sur API >= 11, vous pouvez utiliser :

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

Comme dans le SDK :

public void setDisplayZoomControls (boolean enabled) 

Depuis : Niveau API 11

Définit si les boutons de zoom à l'écran sont utilisés. Une combinaison de contrôles de zoom intégrés activés et contrôles de zoom à l'écran désactivés permet de faire fonctionner le zoom par pincement sans les commandes à l'écran.

10 votes

Dommage que plus de 60 % des utilisateurs utilisent encore l'interface API 11... et je dis cela un an après que vous l'ayez publiée ! A quoi ressemblaient les chiffres quand vous avez posté la suggestion ?

0 votes

Je l'ai utilisé avec cette réponse pour que ma vue soit par défaut dézoomée et que je puisse pincer pour zoomer. J'ai juste laissé de côté la partie affichage pour travailler avec la version pré-API 11.

0 votes

Bonne réponse. Assurez-vous également qu'un autre facteur de contrôle est "user-scalable" dans la méta <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">.

37voto

gngr44 Points 1028

J'ai regardé le code source de WebView et j'ai conclu qu'il n'y a pas de moyen élégant d'accomplir ce que vous demandez.

Ce que j'ai fini par faire est de sous-classer WebView et de remplacer OnTouchEvent . Sur OnTouchEvent para ACTION_DOWN je vérifie combien de pointeurs il y a en utilisant MotionEvent.getPointerCount() . S'il y a plus d'un pointeur, j'appelle setSupportZoom(true) sinon, j'appelle setSupportZoom(false) . J'appelle ensuite le super.OnTouchEvent().

Cela aura pour effet de désactiver le zoom lors du défilement (et donc de désactiver les commandes de zoom) et d'activer le zoom lorsque l'utilisateur est sur le point de pincer le zoom. Ce n'est pas une bonne façon de faire, mais cela a bien fonctionné pour moi jusqu'à présent.

Notez que getPointerCount() a été introduit dans la version 2.1. Vous devrez donc effectuer des opérations supplémentaires si vous utilisez la version 1.6.

1 votes

Merci pour cette solution. Elle fonctionne presque comme je le souhaite. Je vais poster le résumé du code dans la question.

11 votes

Ai-je dit que je t'aime, gngr44 ?

0 votes

Incroyable ! Merci beaucoup :)

29voto

Lukas Knuth Points 14042

Nous avons eu le même problème en travaillant sur une application Android pour un client et j'ai réussi à "hacker" cette restriction.

J'ai jeté un coup d'oeil au code source Android pour la classe WebView et j'ai repéré une updateZoomButtonsEnabled() -méthode qui travaillait avec un ZoomButtonsController -objet pour activer et désactiver les contrôles de zoom en fonction de l'échelle actuelle du navigateur.

J'ai cherché une méthode pour retourner le ZoomButtonsController -et a trouvé le getZoomButtonsController() -méthode qui a retourné cette même instance.

Bien que la méthode soit déclarée public il n'est pas documenté dans le WebView -documentation et Eclipse n'a pas pu le trouver non plus. J'ai donc essayé de réfléchir à cela et j'ai créé mon propre fichier WebView -pour remplacer l'option onTouchEvent() -qui a déclenché les contrôles.

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

Vous pourriez vouloir supprimer les constructeurs inutiles et réagir probablement sur les exceptions.

Bien que cette méthode semble peu fiable, elle permet de fonctionne jusqu'au niveau 4 de l'API (Android 1.6).


Comme @jayellos souligné dans les commentaires, le privé getZoomButtonsController() -n'existe plus sur Android 4.0.4 et plus.

Cependant, ce n'est pas nécessaire. Utilisation de exécution conditionnelle nous pouvons vérifier si nous nous trouvons sur un appareil doté du niveau 11+ de l'API et utiliser la fonctionnalité exposée (cf. @Yuttadhammo réponse) pour masquer les contrôles.

J'ai mis à jour l'exemple de code ci-dessus pour faire exactement cela.

0 votes

@Lukas, cela ne fonctionne pas sur Android 4.0.4. Il renvoie NoSuchMethodException : getZoomButtonsController.

1 votes

@jayellos Sous Android 4, vous pouvez utiliser la fonction WebSettings.setDisplayZoomControls(boolean) qui est disponible à partir du niveau 11 de l'API.

0 votes

@LukasKnuth merci pour votre aide. Maintenant cela fonctionne. J'ai changé mon niveau Api cible à 11+. Comme dit à l'exécution conditionnelle. Avant, mon niveau Api cible était de 10, je ne pouvais donc pas utiliser la fonction .setDisplayZoomControls(boolean). Encore une fois, merci.

10voto

Jacob Nordfalk Points 1505

J'ai modifié un peu la solution de Lukas Knuth :

1) Il n'est pas nécessaire de sous-classer la webview,

2) le code se plantera pendant la vérification du bytecode sur certains appareils Android 1.6 si vous ne mettez pas les méthodes inexistantes dans des classes séparées.

3) Les commandes de zoom apparaîtront toujours si l'utilisateur fait défiler une page vers le haut/bas. Je règle simplement le conteneur du contrôleur de zoom sur la visibilité 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);
  }

0 votes

Une solution parfaite. La seule chose que je changerais est invoke(webview, (Object[]) null)) pour ne pas avoir un avertissement dans Eclipse.

0 votes

Cela semble être une bonne solution. Je ne peux pas compiler à cause de cette erreur : L'appel nécessite le niveau 11 de l'API (le minimum actuel est 8) : Android.webkit.WebSettings#setDisplayZoomControls

0 votes

Appuyez sur Ctrl-1 pour @SuppressLint

7voto

Mihail M Points 71

Lukas Knuth ont bonne solution, mais sur Android 4.0.4 sur Samsung Galaxy SII je cherche toujours les contrôles de zoom. Et je le résous 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);
}

au lieu de

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

0 votes

Je sais que cette réponse date de plusieurs mois, mais je voulais simplement vous remercier. Cette réponse, combinée à celle de Lukas Knuth, est parfaite.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X