Panos
Panos

Reputation: 7427

Android WebView inside ScrollView scrolls only scrollview

In my app I have a ScrollView that contains some linearviews, some textviews and One Webview, then other linear layouts etc. The problem is that the WebView does not scroll. The Scroll listens only on ScrollView. Any suggestions??


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

Upvotes: 48

Views: 55618

Answers (8)

This is more comfortable for me.

public class NestedWebView extends WebView implements NestedScrollingChild {
private final String TAG = getClass().getSimpleName();
private NestedScrollingChildHelper mChildHeper;

public NestedWebView(@NonNull Context context) {
    super(context);
    mChildHeper=new NestedScrollingChildHelper(this);
    setNestedScrollingEnabled(true);
}
public NestedWebView(@NonNull Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    mChildHeper=new NestedScrollingChildHelper(this);
    setNestedScrollingEnabled(true);
}
public NestedWebView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    mChildHeper=new NestedScrollingChildHelper(this);
    setNestedScrollingEnabled(true);
}
public NestedWebView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    mChildHeper=new NestedScrollingChildHelper(this);
    setNestedScrollingEnabled(true);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
    startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
    return super.onTouchEvent(event);
}
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
    super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
    stopNestedScroll();
}
@Override
public void stopNestedScroll() {
    super.stopNestedScroll();
}
@Override
public boolean startNestedScroll(int axes) {
    return super.startNestedScroll(axes);
}
@Override
public void setNestedScrollingEnabled(boolean enabled) {
    super.setNestedScrollingEnabled(enabled);
}

}

Upvotes: 0

Dipendra
Dipendra

Reputation: 1557

The solution provided by @panos works but it still has issues when used with ScrollView. The following enhanced version overcomes that problem.

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

}

Additionally, you might want to have the following settings for your TouchyWebView.

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

Upvotes: 15

gasolin
gasolin

Reputation: 2334

still happens in react-native-webview, issue tracked here https://github.com/react-native-community/react-native-webview/issues/22

Upvotes: 0

Nikunj Paradva
Nikunj Paradva

Reputation: 16097

Just add one line in class file

mWebview.setNestedScrollingEnabled(true);

or add in Webview tag in XML

android:nestedScrollingEnabled="true"

Warning: only for API 21 and 21+

Upvotes: -1

Randy
Randy

Reputation: 1488

Working off the solutions of @Panos and @Dipendra I still had some issues with a mapview inside a scrollview. It would not consistently scroll vertically and the methods were deprecated so I worked out this trick I use with mapview inside of scrollviews and works great. I hope this can help a few of you.

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


}

}

I also followed @Dipendra advice about settings the controls.

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

Upvotes: 1

snachmsm
snachmsm

Reputation: 19273

Panos solution is sufficient for me with one exception... My fixed-height (200dp) WebView may be empty or may have loaded lot of content. So it may be or may be not scrollable "itself". Panos solution is consuming MotionEvents always, so when WebView is empty and user touch WebView and try to scroll then WebView will not scroll (because there is no content) and scrollable parent also, cause WebView "swallows" MotionEvent - so nothing happens. I've added small if statement for expected behaviour:

@Override
public boolean onTouchEvent(MotionEvent event) {
    if(computeVerticalScrollRange() > getMeasuredHeight())
        requestDisallowInterceptTouchEvent(true);
    return super.onTouchEvent(event);
}
  • when WebView is empty and not-vertical-scrollable then computeVerticalScrollRange() == getMeasuredHeight()
  • when WebView have content longer than its height (is scrollable) then computeVerticalScrollRange() > getMeasuredHeight()

Upvotes: 8

Panos
Panos

Reputation: 7427

Here is the solution. Found online. I have subclassed WebView and i'm using the requestDisallowInterceptTouchEvent(true); method to allow my webview to handle the scroll event.

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

And in layout.xml

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

Upvotes: 103

Artyom Kiriliyk
Artyom Kiriliyk

Reputation: 2513

You can change into 3 layouts:

  1. First TextView - header
  2. WebView - main layout
  3. Second TextView - footer


WebView web = (WebView) findViewById(R.id.webView);
View header = getLayoutInflater().inflate(R.layout.header_layout, null);
View footer = getLayoutInflater().inflate(R.layout.foorer_layout, null);
web.addHeaderView(headerComment);
web.addFooterView(footerComment);

Upvotes: -16

Related Questions