9

The NestedScrollView provided with the support library doesn't work properly with the WebView (related bug report). Because of this I have set out to implement NestedScrollingChild for a WebView and it appears to work fine for the first scroll, collapsing and expanding the AppBarLayout but any subsequent scrolls fail to collapse it.

My WebView:

import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.support.v4.view.NestedScrollingChild; import android.support.v4.view.NestedScrollingChildHelper; import android.util.AttributeSet; import android.view.View; import android.webkit.WebView; /** * Created by carlos on 2/19/16. */ public class MyWebView extends WebView implements NestedScrollingChild { private static final String TAG = MyWebView.class.getSimpleName(); private NestedScrollingChildHelper helper = new NestedScrollingChildHelper(this); public MyWebView(Context context) { super(context); } public MyWebView(Context context, AttributeSet attrs) { super(context, attrs); } public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public MyWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } public MyWebView(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) { super(context, attrs, defStyleAttr, privateBrowsing); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { int dx = l - oldl; int dy = t - oldt; if (dy != 0) helper.startNestedScroll(View.SCROLL_AXIS_VERTICAL); helper.dispatchNestedPreScroll(dx, dy, null, null); if (dy != 0) helper.stopNestedScroll(); super.onScrollChanged(l, t, oldl, oldt); } @Override public boolean isNestedScrollingEnabled() { return helper.isNestedScrollingEnabled(); } @Override public void setNestedScrollingEnabled(boolean enabled) { helper.setNestedScrollingEnabled(enabled); } @Override public boolean startNestedScroll(int axes) { return helper.startNestedScroll(axes); } @Override public void stopNestedScroll() { helper.stopNestedScroll(); } @Override public boolean hasNestedScrollingParent() { return helper.hasNestedScrollingParent(); } @Override public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) { return helper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow); } @Override public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { return helper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow); } @Override public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { return helper.dispatchNestedFling(velocityX, velocityY, consumed); } @Override public boolean dispatchNestedPreFling(float velocityX, float velocityY) { return helper.dispatchNestedPreFling(velocityX, velocityY); } } 

My activity:

import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.webkit.WebSettings; import android.webkit.WebViewClient; public class ScrollingActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_scrolling); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); MyWebView view = (MyWebView) findViewById(R.id.webview); view.setNestedScrollingEnabled(true); view.setWebViewClient(new WebViewClient()); WebSettings settings = view.getSettings(); settings.setJavaScriptEnabled(true); settings.setAllowContentAccess(true); settings.setAppCacheEnabled(true); settings.setDatabaseEnabled(true); settings.setDomStorageEnabled(true); settings.setRenderPriority(WebSettings.RenderPriority.HIGH); settings.setJavaScriptEnabled(true); settings.setSupportZoom(true); settings.setJavaScriptCanOpenWindowsAutomatically(true); settings.setBuiltInZoomControls(true); settings.setAppCacheEnabled(true); settings.setAppCachePath(getCacheDir().getAbsolutePath()); settings.setDatabaseEnabled(true); settings.setSupportMultipleWindows(true); settings.setLoadWithOverviewMode(true); settings.setUseWideViewPort(true); settings.setDomStorageEnabled(true); settings.setAllowContentAccess(true); settings.setAllowFileAccess(true); settings.setSaveFormData(true); // findViewById(R.id.nested).setLayerType(View.LAYER_TYPE_HARDWARE, null); // view.setLayerType(View.LAYER_TYPE_HARDWARE, null); view.loadUrl("http://vimeo.com"); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_scrolling, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } } 

My styles.xml

<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> <style name="AppTheme.NoActionBar"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> </style> <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/> <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/> </resources> 

My dimensions file:

<resources> <dimen name="app_bar_height">180dp</dimen> <dimen name="fab_margin">16dp</dimen> <dimen name="text_margin">16dp</dimen> </resources> 

My activity layout (activity_scrolling.xml):

<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.childscrollview.ScrollingActivity"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="@dimen/app_bar_height" android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|snap|enterAlways"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" app:popupTheme="@style/AppTheme.PopupOverlay"/> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <com.childscrollview.MyWebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" ></com.childscrollview.MyWebView> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/fab_margin" android:src="@android:drawable/ic_dialog_email" app:layout_anchor="@id/app_bar" app:layout_anchorGravity="bottom|end"/> </android.support.design.widget.CoordinatorLayout> 

So what is wrong with my implementation or is this a bug?

Thanks.

EDIT: Google now says the WebView isn't supported like this.

2 Answers 2

2

I had tested many WebView, which implements NestedScrollingChild.

However, the only correct implementation, is found at https://github.com/takahirom/webview-in-coordinatorlayout/blob/master/app/src/main/java/com/github/takahirom/webview_in_coodinator_layout/NestedWebView.java

You can use NestedWebView without any modification. It works very smoothly.

I would also like to share my XML files.

web_view_fragment_activity.xml

<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/coordinator_layout" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar_layout" android:layout_width="match_parent" android:layout_height="wrap_content" app:elevation="4dp" android:elevation="4dp" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" > <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar_layout" app:layout_scrollFlags="scroll|enterAlways|snap" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary"> <!-- Toolbar --> <include layout="@layout/toolbar"/> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <!-- http://stackoverflow.com/questions/14171471/remove-vertical-padding-from-horizontal-progressbar --> <!-- http://stackoverflow.com/questions/32464749/horizontal-progress-bar-is-not-visible-if-placed-above-toolbar-for-android-5 --> <ProgressBar style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="8dp" android:id="@+id/progress_bar" android:layout_gravity="top" android:layout_marginBottom="0dp" android:layout_marginTop="-4dp" android:elevation="4dp" android:max="100" /> <FrameLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" android:foreground="?attr/headerShadow" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </android.support.design.widget.CoordinatorLayout> 

A fragment, contains ViewAnimator (Multiple WebView is added into ViewAnimator and a bottom navigation bar.

The fragment is added into content FragmeLayout

web_view_fragment.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/web_view_linear_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center_horizontal" > <ViewAnimator android:id="@+id/web_view_view_animator" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <LinearLayout android:id="@+id/navigation_linear_layout" android:layout_width="match_parent" android:layout_height="48dp" android:background="?attr/colorPrimary" android:orientation="horizontal" > <LinearLayout android:id="@+id/left_linear_layout" android:layout_width="0dp" android:width="0dp" android:layout_weight="0.5" android:layout_height="match_parent" android:gravity="left" android:clickable="true" android:background="?attr/selectableItemBackground" android:theme="@style/Base.ThemeOverlay.AppCompat.Dark" > <ImageView android:id="@+id/left_image_view" android:scaleType="center" android:src="@drawable/ic_chevron_left_white_24dp" android:layout_width="48dp" android:layout_height="match_parent" /> </LinearLayout> <LinearLayout android:id="@+id/right_linear_layout" android:layout_width="0dp" android:width="0dp" android:layout_weight="0.5" android:layout_height="match_parent" android:gravity="right" android:clickable="true" android:background="?attr/selectableItemBackground" android:theme="@style/Base.ThemeOverlay.AppCompat.Dark" android:orientation="horizontal"> <TextView android:id="@+id/next_text_view" android:layout_width="0dp" android:width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:gravity="center_vertical|right" android:ellipsize="end" android:textSize="12sp" android:maxLines = "2" android:minLines = "1" android:lineSpacingMultiplier="1.2"/> <ImageView android:id="@+id/right_image_view" android:scaleType="center" android:src="@drawable/ic_chevron_right_white_24dp" android:layout_width="48dp" android:layout_height="match_parent" /> </LinearLayout> </LinearLayout> </LinearLayout> 

Here's the outcome

Outcome before scrolling

enter image description here

Outcome after scrolling

enter image description here

Sign up to request clarification or add additional context in comments.

4 Comments

Does it work with sites that keep growing? That was my issue last time I tried this. I think vimeo was the site that was giving me issues.
May I know what do you mean sites that keep growing? I had tested NestedWebView.java implementation across many different sites, no issue found so far. The scroll behavior is quite smooth and nice.
Sites that give you more data when you get to bottom. They have some sort of list of videos, stories, posts, etc, and when you reach the bottom they give you more. The issue I had is that those sites could not detect that the bottom was reached.
If you have such site URL, I can test it for u on my site.
-1

What i suggest you Use fragment inside your main xml file .Inside fragment you use webview may be this resolve your problem.

2 Comments

Do I do that with a NestedScrollView? where do I put @string/appbar_scrolling_view_behavior? can you give an example?
This does not solve the issue, placing a view inside a fragment does not change the structure of the view hierarchy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.