Désactiver le défilement dans la vue Web?

86

Jusqu'à présent, je n'ai été qu'un développeur iPhone et maintenant j'ai décidé de donner un tourbillon à Android. Quelque chose que je n'ai pas été en mesure de comprendre sur Android, c'est comment empêcher par programme le défilement dans un WebView?

Quelque chose de similaire à la prévention de l' onTouchMoveévénement par les iPhones serait génial!

Jake Sankey
la source

Réponses:

179

Voici mon code pour désactiver tout le défilement dans la vue Web:

  // disable scroll on touch
  webview.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      return (event.getAction() == MotionEvent.ACTION_MOVE);
    }
  });

Pour masquer uniquement les barres de défilement, mais pas désactiver le défilement:

WebView.setVerticalScrollBarEnabled(false);
WebView.setHorizontalScrollBarEnabled(false);

ou vous pouvez essayer d'utiliser la disposition à une seule colonne, mais cela ne fonctionne qu'avec des pages simples et cela désactive le défilement horizontal:

   //Only disabled the horizontal scrolling:
   webview.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);

Vous pouvez également essayer d' encapsuler votre vue Web avec une vue de défilement à défilement vertical et désactiver tout le défilement sur la vue Web:

<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="vertical"    >
  <WebView
    android:id="@+id/mywebview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:scrollbars="none" />
</ScrollView>

Et mettre

webview.setScrollContainer(false);

N'oubliez pas d'ajouter le webview.setOnTouchListener(...)code ci-dessus pour désactiver tout le défilement dans la vue Web. Le ScrollView vertical permettra de faire défiler le contenu de la WebView.

peceps
la source
fonctionne bien, mais après quelques secondes, cela provoque un crash sur Samsung i5700 spica dans /system/lib/libwebcore.so.
Lukas
LayoutAlgorithm.SINGLE_COLUMN ou webview.setOnTouchListener?
peceps
3
Si vous placez un WebView dans un ScrollView, définissez l'attribut android: isScrollContainer de WebView sur "false" plutôt que de définir android: scrollbars sur "none". Cela a pour effet de désactiver complètement la gestion du défilement de la vue Web et lui permet de se développer en fonction de son contenu. Le défilement sera alors géré uniquement par le ScrollView parent.
BladeCoder
1
Si vous avez besoin de gérer des MotionEvent.ACTION_MOVEévénements dans votre WebViewvoir ma réponse ci-dessous.
GDanger
1
Ignorant la ACTION_MOVEsur l' setOnTouchListenerévénement a des effets secondaires , donc je ne recommanderais pas cette réponse; 1. Les balayages rapides sont comptés comme des onclickévénements sur la page. 2. Empêche le défilement excessif des éléments sur la page, cela peut être nécessaire pour une interaction appropriée selon le site. 3. L' touchmoveévénement JS . @GDanger a la bonne réponse qui remplace le overScrollByen étendant le WebViewcar il n'a aucun effet secondaire, empêche simplement le défilement de la page. stackoverflow.com/a/26129301/1244574
jkasten
22

Je ne sais pas si vous en avez encore besoin ou non, mais voici la solution:

appView = (WebView) findViewById(R.id.appView); 
appView.setVerticalScrollBarEnabled(false);
appView.setHorizontalScrollBarEnabled(false);
umar
la source
18
D'accord. cela désactive les barres de défilement, mais cela n'empêche pas le défilement par glissement. Il semble que le html doit s'adapter aussi ...
rdmueller
Si vous concevez vos pages Web uniquement pour la vue Web Android, je vous recommande de créer vos pages Web dans un tableau. La largeur doit être comme width = "100%" et identique pour la hauteur. il n'y aura donc plus de traînage.
umar
width = 100% ne fonctionne pas toujours, par exemple: stackoverflow.com/questions/6460871/…
NoBugs
génial ... c'est ce dont j'ai besoin. Merci
Peter
21

Faire WebViewignorer les événements de mouvement n'est pas la bonne façon de procéder. Et si le WebViewbesoin d'entendre parler de ces événements?

Au lieu de cela, sous WebView-classez et remplacez les méthodes de défilement non privées.

public class NoScrollWebView extends WebView {
    ...
    @Override
    public boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, 
                                int scrollRangeX, int scrollRangeY, int maxOverScrollX, 
                                int maxOverScrollY, boolean isTouchEvent) {
        return false;
    }

    @Override
    public void scrollTo(int x, int y) {
        // Do nothing
    }

    @Override
    public void computeScroll() {
        // Do nothing
    }
}

Si vous regardez la source de pour WebViewvous pouvez voir que les onTouchEventappels doDragqui appelle overScrollBy .

GDanger
la source
1
Si vous avez besoin de désactiver / activer le défilement par programme, regardez l' essentiel que j'ai créé.
GDanger
1
Votre méthode fonctionne pour moi. Et je suis tout à fait d'accord avec vous. Dans mon cas, je ne peux pas faire glisser la barre de progression vidéo et audio intégrée dans WebView en utilisant la réponse d'acceptation.
codezjx
C'est la bonne réponse. Bien qu'il ait besoin de quelques ajustements sur les principaux constructeurs. Veuillez regarder ma réponse complète ci-dessous. stackoverflow.com/a/51936944/393502
Vansi
13

L'ajout des détails de la marge au corps empêchera le défilement si votre contenu s'emballe correctement, comme suit:

<body leftmargin="0" topmargin="0" rightmargin="0" bottommargin="0">

Assez facile, et beaucoup moins de code + de surcharge de bogue :)

Auri Rahimzadeh
la source
1
Brillant! +1 pour une solution simple HTML uniquement. Parfois, je souhaite, la mise en page sous Android était aussi simple que css ...
Pritesh Desai
Cela a l'air bien dans le navigateur Android d'origine, mais ne semble pas fonctionner dans Firefox (Fennec) ... malgré qu'il n'y ait rien à faire défiler horizontalement, Firefox me laisse toujours faire défiler vers la droite au point où tout le contenu a défilé hors de l'écran.
Michael le
1
Ne fonctionne pas sur WebView moderne (Android 5 et supérieur)
Roel
8

Définissez un écouteur sur votre WebView:

webView.setOnTouchListener(new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                return(event.getAction() == MotionEvent.ACTION_MOVE));
            }
        });
user322987
la source
3
Il y a une parenthèse supplémentaire à la fin de la returnligne. Cela interrompt également les événements tactiles HTML5 et JavaScript.
Rohan Singh
Cela le désactive certainement, mais comment puis-je tuer l'auditeur plus tard pour une entrée renable? J'ai essayé event.getAction() != MotionEvent.ACTION_MOVEaussi bien quereturn true
CQM
Le cas standard du «ne rien faire» ne l'est return falsepas return true.
Matthew Lire
6

Je n'ai pas essayé cela car je n'ai pas encore rencontré ce problème, mais vous pourriez peut-être surcharger la fonction onScroll?

@Override
public void scrollTo(int x, int y){
super.scrollTo(0,y);
}
ZeroTruths
la source
C'est ce que nous appelons en Inde un Jugaad ... bien que cela fonctionne très bien
R4chi7
4

Ma solution sale, mais facile à mettre en œuvre et qui fonctionne bien:

Mettez simplement la vue Web dans une vue de défilement. Faites en sorte que la vue Web soit beaucoup trop grande que le contenu possible (dans une ou les deux dimensions, selon les exigences). ..et configurez les barres de défilement de la vue de défilement comme vous le souhaitez.

Exemple de désactivation de la barre de défilement horizontale sur une vue Web:

<ScrollView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:scrollbars="vertical"
>
    <WebView
        android:id="@+id/mywebview"
        android:layout_width="1000dip"
        android:layout_height="fill_parent"
    />
</ScrollView>

J'espère que ça aide ;)

user289463
la source
oui, mais alors la taille du rouleau ne serait pas trop grande avec beaucoup d'espace blanc en bas?
Rafael Sanches
1
Et si la largeur du contenu était de 1001dp?
Waltsu
3

J'ai résolu le scintillement et le défilement automatique en:

webView.setFocusable(false);
webView.setFocusableInTouchMode(false);

Cependant, si cela ne fonctionne toujours pas pour une raison quelconque, créez simplement une classe qui étend WebView et mettez cette méthode dessus:

// disable scroll on touch
  setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      return (event.getAction() == MotionEvent.ACTION_MOVE);
    }
  });

Je suggère d'étendre WebView, afin de fournir un contrôle plus efficace, comme désactiver / activer les balayages, activer / désactiver les touches, les écouteurs, contrôler les transitions, les animations, définir les paramètres en interne, etc.

Abhinav Saxena
la source
3

Pour désactiver le défilement, utilisez ceci

webView.setOnTouchListener(new View.OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) 
    {
        return (event.getAction() == MotionEvent.ACTION_MOVE);
    }
});
Saba Chaudry
la source
2

Ce n'est peut-être pas la source de votre problème, mais j'ai passé des heures à essayer de comprendre pourquoi mon application qui fonctionnait bien sur l'iphone faisait que le navigateur Android lançait constamment les barres de défilement verticales / horizontales et déplaçait réellement la page. J'avais une balise de corps html avec une hauteur et une largeur réglées à 100%, et le corps était plein de diverses balises à différents endroits. Peu importe ce que j'ai essayé, les navigateurs Android afficheraient leurs barres de défilement et déplaceraient un peu la page, en particulier lors d'un balayage rapide. La solution qui a fonctionné pour moi sans avoir à faire quoi que ce soit dans un APK était d'ajouter ce qui suit à la balise body:

leftmargin="0" topmargin="0"

Il semble que les marges par défaut pour la balise corporelle étaient appliquées sur le droïde mais ignorées sur l'iphone

Robert Etheredge
la source
1

Si vous sous- classez Webview, vous pouvez simplement remplacer onTouchEvent pour filtrer les événements de déplacement qui déclenchent le défilement.

public class SubWebView extends WebView {

    @Override
    public boolean onTouchEvent (MotionEvent ev)    {
        if(ev.getAction() == MotionEvent.ACTION_MOVE) {
            postInvalidate();
            return true;
        }
        return super.onTouchEvent(ev);
    }
    ...
mischka
la source
0

étudier les réponses ci-dessus a presque fonctionné pour moi ... mais j'avais toujours un problème en ce que je pouvais «lancer» la vue sur 2.1 (semblait être corrigé avec 2.2 et 2.3).

voici ma solution finale

public class MyWebView extends WebView
{
private boolean bAllowScroll = true;
@SuppressWarnings("unused") // it is used, just java is dumb
private long downtime;

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

public void setAllowScroll(int allowScroll)
{
    bAllowScroll = allowScroll!=0;
    if (!bAllowScroll)
        super.scrollTo(0,0);
    setHorizontalScrollBarEnabled(bAllowScroll);
    setVerticalScrollBarEnabled(bAllowScroll);
}

@Override
public boolean onTouchEvent(MotionEvent ev) 
{
    switch (ev.getAction())
    {
    case MotionEvent.ACTION_DOWN:
        if (!bAllowScroll)
            downtime = ev.getEventTime();
        break;
    case MotionEvent.ACTION_CANCEL:
    case MotionEvent.ACTION_UP:
        if (!bAllowScroll)
        {
            try {
                Field fmNumSamples = ev.getClass().getDeclaredField("mNumSamples");
                fmNumSamples.setAccessible(true);
                Field fmTimeSamples = ev.getClass().getDeclaredField("mTimeSamples");
                fmTimeSamples.setAccessible(true);
                long newTimeSamples[] = new long[fmNumSamples.getInt(ev)];
                newTimeSamples[0] = ev.getEventTime()+250;
                fmTimeSamples.set(ev,newTimeSamples);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        break;
    }
    return super.onTouchEvent(ev);
}

@Override
public void flingScroll(int vx, int vy)
{
    if (bAllowScroll)
        super.flingScroll(vx,vy);
}

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt)
{
    if (bAllowScroll)
        super.onScrollChanged(l, t, oldl, oldt);
    else if (l!=0 || t!=0)
        super.scrollTo(0,0);
}

@Override
public void scrollTo(int x, int y)
{
    if (bAllowScroll)
        super.scrollTo(x,y);
}

@Override
public void scrollBy(int x, int y)
{
    if (bAllowScroll)
        super.scrollBy(x,y);
}
}
SteelBytes
la source
Remplacer la méthode onScrollChanged () fonctionne pour moi. Dans mon cas, je ne peux pas faire glisser la barre de progression vidéo et audio intégrée dans WebView en utilisant la réponse d'acceptation. Merci beaucoup!
codezjx
-1

Cela devrait être la réponse complète. Comme suggéré par @GDanger. Étendez WebView pour remplacer les méthodes de défilement et incorporer la vue Web personnalisée dans le format xml.

public class ScrollDisabledWebView extends WebView {

    private boolean scrollEnabled = false;

    public ScrollDisabledWebView(Context context) {
        super(context);
        initView(context);
    }

    public ScrollDisabledWebView(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        initView(context);
    }
    // this is important. Otherwise it throws Binary Inflate Exception.
    private void initView(Context context) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    }

    @Override
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,
                                   int scrollRangeX, int scrollRangeY, int maxOverScrollX,
                                   int maxOverScrollY, boolean isTouchEvent) {
        if (scrollEnabled) {
            return super.overScrollBy(deltaX, deltaY, scrollX, scrollY,
                    scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
        }
        return false;
    }

    @Override
    public void scrollTo(int x, int y) {
        if (scrollEnabled) {
            super.scrollTo(x, y);
        }
    }

    @Override
    public void computeScroll() {
        if (scrollEnabled) {
            super.computeScroll();
        }
    }
}

Et puis incorporer dans le fichier de mise en page comme suit

<com.sample.apps.ScrollDisabledWebView
    android:id="@+id/webView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"
    tools:context="com.sample.apps.HomeActivity"/>

Ensuite, dans l'activité, utilisez également des méthodes supplémentaires pour désactiver les barres de défilement.

ScrollDisabledWebView webView = (ScrollDisabledWebView) findViewById(R.id.webView);
webView.setVerticalScrollBarEnabled(false);
webView.setHorizontalScrollBarEnabled(false);
Vansi
la source
-3

Utilisez simplement android:focusableInTouchMode="false"sur votre webView .

Socratex
la source