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 >
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"
/>
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);
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 MotionEvent
s, 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);
}
WebView
est vide et ne peut pas défiler verticalement alors computeVerticalScrollRange() == getMeasuredHeight()
WebView
a un contenu plus long que sa hauteur (peut défiler) alors computeVerticalScrollRange() > getMeasuredHeight()
mWebview.setNestedScrollingEnabled(true);
ou ajoutez une balise Webview
en XML
Android:nestedScrollingEnabled="true"
Avertissement: uniquement pour API 21 et 21+
arrive toujours dans react-native-webview
, problème suivi ici https://github.com/react-native-community/react-native-webview/issues/22
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);