18

I've got an activity that use WebView to load the web content. The problem arise when I want to implement Flexible Space with image. I can expand and collapse the Toolbar, but when the Toolbar already collapsed, The scrollbar stuck there. I can't scroll the content inside the WebView.

This is the XML:

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:fillViewport="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <WebView
        android:id="@+id/read_full_content_wv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>


</android.support.v4.widget.NestedScrollView>

Do you have any solution for this?

Regards, Elmer


EDIT After I look at the link that given by LinX64. I tried to add:

public class FullContentActivity extends AppCompatActivity {
   ...
   @Override
   protected void onCreate(Bundle savedInstance){
      ...
      WebView webView = (WebView) findViewById(R.id.read_full_content_wv);
      webView.setWebViewClient(new MyBrowser());
      webView.loadData(extra.get(1).toString(), "text/html", "utf-8");
      ...
   }
   ...
   private class MyBrowser extends WebViewClient {
      @Override
      public void onPageStarted(WebView view, String url, Bitmap favicon){
         NestedScrollView nsv = (NestedScrollView) findViewById(R.id.nsv_fc);
         nsv.scrollTo(0,0);
      }
   }
}

and still got stucked.


EDIT 2 FYI: I tried on ASUS Zenfone 6 - KitKat 4.4.2 Is it possible KitKat can't load it correctly?


EDIT 3: The best solution I've got for this question

After working around, I think I cannot get experience I want for Flexible Space using CollapsingToolbarLayout combined with WebView, so I changed WebView to TextView and use Html.fromHtml() to read the content. Unless Google gonna update or fix some features so we can combine CollapsingToolbarLayout and WebView together.

j.elmer
  • 1,441
  • 2
  • 17
  • 36
  • Check this: http://stackoverflow.com/a/32627944/4409113 – ʍѳђઽ૯ท Feb 01 '16 at 10:27
  • After you show, that link, I tried and still stucked. I create class like this `private class MyBrowser extends WebViewClient { @Override public void onPageStarted(WebView view, String url, Bitmap favicon){ NestedScrollView nsv = (NestedScrollView) findViewById(R.id.nsv_fc); nsv.scrollTo(0,0); } }` and call it like this at onCreate of the activity `WebView webView = (WebView) findViewById(R.id.read_full_content_wv); webView.setWebViewClient(new MyBrowser()); webView.loadData(extra.get(1).toString(), "text/html", "utf-8");` – j.elmer Feb 01 '16 at 10:55
  • please add these codes in your question and be clear what have you tried. – ʍѳђઽ૯ท Feb 01 '16 at 11:50
  • sorry for the inconvenience, I already add new information in my question @LinX64. – j.elmer Feb 01 '16 at 12:26
  • Now, it looks better :) – ʍѳђઽ૯ท Feb 01 '16 at 12:28

7 Answers7

20

By the usage of NestedScrollingChild Interface, we can implements the NestedScrollView properties in the webview. And customize the scrolling functionality under the onTouchEvent() method.

public class NestedWebView extends WebView implements NestedScrollingChild {
    private int mLastY;
    private final int[] mScrollOffset = new int[2];
    private final int[] mScrollConsumed = new int[2];
    private int mNestedOffsetY;
    private NestedScrollingChildHelper mChildHelper;

    public NestedWebView(Context context) {
        this(context, null);
    }

    public NestedWebView(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.webViewStyle);
    }

    public NestedWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mChildHelper = new NestedScrollingChildHelper(this);
        setNestedScrollingEnabled(true);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean returnValue = false;

        MotionEvent event = MotionEvent.obtain(ev);
        final int action = MotionEventCompat.getActionMasked(event);
        if (action == MotionEvent.ACTION_DOWN) {
            mNestedOffsetY = 0;
        }
        int eventY = (int) event.getY();
        event.offsetLocation(0, mNestedOffsetY);
        switch (action) {
            case MotionEvent.ACTION_MOVE:
                int totalScrollOffset = 0;
                int deltaY = mLastY - eventY;
                // NestedPreScroll
                if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
                    totalScrollOffset += mScrollOffset[1];
                    deltaY -= mScrollConsumed[1];
                    event.offsetLocation(0, -mScrollOffset[1]);
                    mNestedOffsetY += mScrollOffset[1];
                }
                returnValue = super.onTouchEvent(event);

                // NestedScroll
                if (dispatchNestedScroll(0, mScrollOffset[1], 0, deltaY, mScrollOffset)) {
                    totalScrollOffset += mScrollOffset[1];
                    event.offsetLocation(0, mScrollOffset[1]);
                    mNestedOffsetY += mScrollOffset[1];
                    mLastY -= mScrollOffset[1];
                }
                mLastY = eventY - totalScrollOffset;
                break;
            case MotionEvent.ACTION_DOWN:
                returnValue = super.onTouchEvent(event);
                mLastY = eventY;
                // start NestedScroll
                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                returnValue = super.onTouchEvent(event);
                // end NestedScroll
                stopNestedScroll();
                break;
        }
        return returnValue;
    }

    // Nested Scroll implements
    @Override
    public void setNestedScrollingEnabled(boolean enabled) {
        mChildHelper.setNestedScrollingEnabled(enabled);
    }

    @Override
    public boolean isNestedScrollingEnabled() {
        return mChildHelper.isNestedScrollingEnabled();
    }

    @Override
    public boolean startNestedScroll(int axes) {
        return mChildHelper.startNestedScroll(axes);
    }

    @Override
    public void stopNestedScroll() {
        mChildHelper.stopNestedScroll();
    }

    @Override
    public boolean hasNestedScrollingParent() {
        return mChildHelper.hasNestedScrollingParent();
    }

    @Override
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed,
                                        int[] offsetInWindow) {
        return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
    }

    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
        return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
    }

    @Override
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
        return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
    }

    @Override
    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
        return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
    }

}

Declare NestedWebView instead of declaring webview inside the NestedScrollView.For example,

<com.nestedscrollwebviewexample.NestedWebView
        android:id="@+id/nested_webview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#000000"
        android:fillViewport="true"
        android:focusable="true"
        android:isScrollContainer="false"
        android:visibility="visible"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        app:layout_scrollFlags="scroll|exitUntilCollapsed" />

Instead of declaring Webview you can initialize as NestedWebView inside your Activity

 private NestedWebView mShopWebView;
        mShopWebView = (NestedWebView) findViewById(R.id.url_load_webview);
PrzemekTom
  • 1,328
  • 1
  • 13
  • 34
Sujai
  • 208
  • 2
  • 6
  • 1
    Good answer, it really helped me – tomassilny Sep 13 '18 at 14:46
  • 1
    There's a bug in the code: `mLastY = eventY - mScrollOffset[1];` is in `if` - there's no guarantee that `mLastY` is updated with `eventY` value. I had an issue with that. I removed this line, then I've created `var totalScrollOffset = 0` on top of `ACTION_MOVE`. Then accumulated `totalScrollOffset += mScrollOffset[1]` inside `if (dispatchNestedPreScroll) and (dispatchNestedScroll)`. Then at the bottom of `ACTION_MOVE` I wrote `mLastY = eventY - totalScrollOffset` – PrzemekTom Feb 06 '19 at 09:18
  • Why aforementioned is actually an issue? Because if `dispatchNestedPreScroll` is not fulfilled, then `mLastY` value gets incremented high and this higher value is dispatched by scroll events, which can make unexpected results (I had an issue with SwipeRefreshLayout) – PrzemekTom Feb 06 '19 at 09:29
  • you are right @Przemo please update the answer to help others. I faced the same issue while zooming where 'mLastY' value was getting incremented automatically. – akshay bhange Apr 08 '19 at 06:46
  • I'm facing a problem in this, when I try to zoom into webpage for the first time it starts zooming in too much. later when I recreate the same fragment, it works properly. any solution ? – akshay bhange Apr 08 '19 at 09:17
14

Got this one working with changing the height attribute of the underlying Webview.

For NestedScrollView use attribute

android:fillViewport="true"

and for WebView use android:layout_height="wrap_content"

Full Answer here

sud007
  • 5,824
  • 4
  • 56
  • 63
  • @akshaybhange this got me working after a long haul of troubleshooting with m xmls. Please thoroughly verify your xml layouts or this or this may also depend on your layout complexity. – sud007 Jan 11 '19 at 06:35
  • 1
    Not working for me, tge webview and nestedscrollview freezes and I can scroll at all. On the other hand when I set fillviewport to 'false' I can scroll but the webview inside nested_sv shows static content and sticky buttons of my website not going down with the scrolling – Barel elbaz Mar 21 '21 at 14:10
  • height size of webview is going to be very small – user924 Sep 14 '21 at 18:23
4

I faced a similar problem but I solved it on multiple Android versions by using the following custom WebView class which manages the touch events:

 import android.content.Context;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.webkit.WebView;

/**
 * Created by pk on 10/16/16.
 * Creates a WebView that can be used inside a ScrollView
 */

public class CustomWebView extends WebView {

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

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

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        //Check pointer index to avoid -1 (error)
        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);


    }
}
CodesmithX
  • 246
  • 4
  • 8
  • 1
    I had to change the check in `onTouchEvent` to: `if (event.getPointerCount() >= 1)`, then it worked for me. Thank you. This should be the accepted answer. – Sakiboy Apr 02 '17 at 10:31
  • 1
    I take it back, this cancels out any collapsing toolbar features... making it a pointless subclass.... – Sakiboy Apr 02 '17 at 11:45
3

Just make NestedScrollView fillViewport = "false" and WebView layout_height = "wrap_content"

<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="false"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<WebView
    android:id="@+id/read_full_content_wv"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

neaenaa
  • 47
  • 1
  • 2
1

As @sud007 answered and referred a link to the full of correct answer, it looked that his short explain here has made confused to people not having read the reference in the link he gave. The correct answer gave a solution look like this

<AppBar></AppBar>
<androidx.core.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true" // Pay attention to this
    android:background="@drawable/bg_content"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"> // Pay attention to this
        <WebView
            android:id="@+id/wv_meal_detail_view_more"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" // Pay attention to this
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="@dimen/dp_30"
            android:scrollbars="none"
            android:layout_marginHorizontal="@dimen/dp_20"/>
     </androidx.constraintlayout.widget.ConstraintLayout>
 </androidx.core.widget.NestedScrollView>

We can use FrameLayout or LinearLayout as well and there is no need to create a custom WebView for this issue. A lot of thanks to @sud007

0

Solution: Just change webView's height match_parent to wrap_content .

When you do height = "match_parent" then webview Not scroll in ScrollView

        android:id="@+id/read_full_content_wv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" // just change height of webView
/> ```
AG-Developer
  • 361
  • 2
  • 10
-1

I see it's been awhile, but i'll try anyway

I had a similar problem.

I solved it by replacing: android.support.v4.widget.NestedScrollView with: android.widget.ScrollView I don't know how it will affect on the collapsing toolbar.

maya
  • 1
  • 1