web-dev-qa-db-fra.com

Android WebView dans ScrollView fait défiler uniquement scrollview

Dans mon application, j'ai un ScrollView qui contient des vues linéaires, des vues de texte et une Webview, puis d'autres dispositions linéaires, etc. Le problème est que la WebView ne défile pas. Le défilement écoute uniquement sur ScrollView. Aucune suggestion??


<ScrollView >
    <TextView />
    <WebView />              <-- this does not scroll
    <TextView />
</ScrollView >
31
Panos

Voici la solution. Trouvé en ligne. J'ai sous-classé WebView et j'utilise la méthode requestDisallowInterceptTouchEvent(true); pour permettre à ma vue Web de gérer l'événement de défilement.

TouchyWebView.Java

package com.mypackage.common.custom.Android.widgets

public class TouchyWebView extends WebView {

    public TouchyWebView(Context context) {
        super(context);
    }

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

    public TouchyWebView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event){
        requestDisallowInterceptTouchEvent(true);
        return super.onTouchEvent(event);
    }          
}

Et dans layout.xml

<com.mypackage.common.custom.Android.widgets.TouchyWebView 
                Android:id="@+id/description_web"
                Android:layout_width="match_parent"
                Android:layout_height="wrap_content"
                 />
80
Panos

La solution fournie par @panos fonctionne mais elle a toujours des problèmes lorsqu'elle est utilisée avec ScrollView. La version améliorée suivante résout ce problème.

public class TouchyWebView extends WebView {

public TouchyWebView(Context context) {
  super(context);
}

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

public TouchyWebView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
}

    @Override
    public boolean onTouchEvent(MotionEvent event) {

  //Check is required to prevent crash
  if (MotionEventCompat.findPointerIndex(event, 0) == -1) {
    return super.onTouchEvent(event);
  }

  if (event.getPointerCount() >= 2) {
    requestDisallowInterceptTouchEvent(true);
  } else {
    requestDisallowInterceptTouchEvent(false);
  }

  return super.onTouchEvent(event);
}

@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
  super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
  requestDisallowInterceptTouchEvent(true);


 }

  }

En outre, vous souhaiterez peut-être disposer des paramètres suivants pour votre TouchyWebView.

mWebView.getSettings().setLoadWithOverviewMode(true);
mWebView.getSettings().setUseWideViewPort(true);
mWebView.getSettings().setSupportZoom(true);
mWebView.getSettings().setBuiltInZoomControls(true);
11
Dipendra

La solution Panos me suffit à une exception près ... Ma hauteur fixe (200dp) WebView peut être vide ou peut avoir chargé beaucoup de contenu. Il peut donc être ou ne pas défiler "lui-même". La solution Panos consomme toujours MotionEvents, donc quand WebView est vide et que l'utilisateur touche WebView et essaie de faire défiler alors WebView ne défilera pas (car il n'y a pas contenu) et le parent déroulant provoquent également WebView "avale" MotionEvent - donc rien ne se passe. J'ai ajouté une petite instruction if pour le comportement attendu:

@Override
public boolean onTouchEvent(MotionEvent event) {
    if(computeVerticalScrollRange() > getMeasuredHeight())
        requestDisallowInterceptTouchEvent(true);
    return super.onTouchEvent(event);
}
  • lorsque WebView est vide et ne peut pas défiler verticalement alors computeVerticalScrollRange() == getMeasuredHeight()
  • lorsque WebView a un contenu plus long que sa hauteur (peut défiler) alors computeVerticalScrollRange() > getMeasuredHeight()
4
snachmsm

Ajoutez simplement une ligne dans le fichier de classe

mWebview.setNestedScrollingEnabled(true);

ou ajoutez une balise Webview en XML

Android:nestedScrollingEnabled="true"

Avertissement: uniquement pour API 21 et 21+

2
Nikunj Paradva

arrive toujours dans react-native-webview, problème suivi ici https://github.com/react-native-community/react-native-webview/issues/22

0
gasolin

En travaillant sur les solutions de @Panos et @Dipendra, j'avais encore quelques problèmes avec une vue de carte dans une vue de défilement. Il ne ferait pas défiler verticalement de manière cohérente et les méthodes étaient obsolètes, j'ai donc élaboré cette astuce que j'utilise avec mapview à l'intérieur des vues de défilement et qui fonctionne très bien. J'espère que cela peut aider certains d'entre vous.

public class TouchyWebView extends WebView {
ViewParent mViewParent;

public TouchyWebView(Context context) {
    super(context);
}

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

public TouchyWebView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

public void setViewParent(@Nullable final ViewParent viewParent) { //any ViewGroup
    mViewParent = viewParent;
}


@Override
public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            if (null == mViewParent) {
                getParent().requestDisallowInterceptTouchEvent(true);
            } else {
                mViewParent.requestDisallowInterceptTouchEvent(true);
            }
            break;
        case MotionEvent.ACTION_UP:
            if (null == mViewParent) {
                getParent().requestDisallowInterceptTouchEvent(false);
            } else {
                mViewParent.requestDisallowInterceptTouchEvent(false);
            }
            break;
        default:
            break;
    }
    return super.onTouchEvent(event);
}

@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
    super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
    requestDisallowInterceptTouchEvent(true);


}

}

J'ai également suivi les conseils de @Dipendra sur la configuration des commandes.

mWebView.getSettings().setLoadWithOverviewMode(true);
mWebView.getSettings().setUseWideViewPort(true);
mWebView.getSettings().setSupportZoom(true);
mWebView.getSettings().setBuiltInZoomControls(true);
0
Randy