j.elmer
j.elmer

Reputation: 1451

WebView inside NestedScrollView cannot be scrolled

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.

Upvotes: 18

Views: 22819

Answers (7)

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

Upvotes: 1

AG-Developer
AG-Developer

Reputation: 359

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
/> ```

Upvotes: 0

neaenaa
neaenaa

Reputation: 45

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"/>

Upvotes: 2

Sujai
Sujai

Reputation: 208

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

Upvotes: 20

sud007
sud007

Reputation: 6161

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

Upvotes: 15

CodesmithX
CodesmithX

Reputation: 274

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


    }
}

Upvotes: 4

maya
maya

Reputation: 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.

Upvotes: -1

Related Questions