I have an Activity with WebView and my own AppBarLayout. I want to implement hiding/showing the AppBarLayout with animation when scrolling the WebView, like in the Google Chrome app.
I tried different ways.
ObservableWebView, but it doesn’t work correctly, it doesn’t always show AppBar, especially if the page is short.
ConstraintLayout with animations. Something similar, but still not the same as in Google Chrome.
Coordinator layout. This is the best variant, I think. But it have some bugs.
I have wrote the code of layout like this:
<?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:id="@+id/main_content" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/appBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@android:color/white" app:layout_scrollFlags="scroll|enterAlways"> <View android:id="@+id/linkFrame" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorPrimary" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> <HorizontalScrollView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:background="@drawable/frame_link_browser" android:padding="8dp" app:layout_constraintBottom_toBottomOf="@+id/linkFrame" app:layout_constraintEnd_toStartOf="@+id/pauseButton" app:layout_constraintStart_toEndOf="@+id/linkDivider" app:layout_constraintTop_toTopOf="@+id/linkFrame"> <TextView android:id="@+id/linkTextView" style="@style/BrowserSmallSecondaryText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:maxLines="1" android:textColor="@color/textPrimary" android:textIsSelectable="true" tools:text="https://vk.com/id118573338" tools:visibility="visible" /> </HorizontalScrollView> <View android:id="@+id/linkDivider" style="@style/VerticalDivider" android:layout_height="24dp" android:layout_centerVertical="true" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:background="#90FFFFFF" android:textColor="@color/textPrimary" app:layout_constraintBottom_toBottomOf="@+id/timerTextView" app:layout_constraintStart_toEndOf="@+id/timerTextView" app:layout_constraintTop_toTopOf="@+id/timerTextView" tools:visibility="visible" /> <TextView android:id="@+id/timerTextView" style="@style/BrowserMiddlePrimaryText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:gravity="center_vertical" app:layout_constraintBottom_toBottomOf="@+id/linkFrame" app:layout_constraintStart_toStartOf="@+id/linkFrame" app:layout_constraintTop_toTopOf="@+id/linkFrame" tools:text="30" /> <TextView android:id="@+id/noInternetTextView" style="@style/BrowserBigPrimaryText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginLeft="16dp" android:text="@string/no_internet_connection" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/noInternetAdditionalTextView" style="@style/BrowserSmallSecondaryText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/no_internet_connection_additional" android:visibility="gone" app:layout_constraintLeft_toLeftOf="@+id/noInternetTextView" app:layout_constraintTop_toBottomOf="@+id/noInternetTextView" /> <ImageButton android:id="@+id/pauseButton" android:layout_width="44dp" android:layout_height="44dp" android:background="@color/transparent" android:text="@string/pause" app:layout_constraintBottom_toBottomOf="@+id/linkFrame" app:layout_constraintEnd_toStartOf="@+id/settingsButton" app:layout_constraintTop_toTopOf="@+id/linkFrame" app:srcCompat="@drawable/ic_pause_circle_filled_white_36dp" tools:visibility="visible" /> <ImageButton android:id="@+id/settingsButton" android:layout_width="44dp" android:layout_height="44dp" android:background="@color/transparent" android:text="@string/settings" app:layout_constraintBottom_toBottomOf="@+id/linkFrame" app:layout_constraintEnd_toEndOf="@+id/linkFrame" app:layout_constraintTop_toTopOf="@+id/linkFrame" app:srcCompat="@drawable/ic_settings_white_36dp" tools:visibility="visible" /> </android.support.constraint.ConstraintLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefresh" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" android:orientation="vertical"> <ProgressBar android:id="@+id/progressBar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="4dp" android:indeterminate="false" android:max="100" android:progress="0" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> <com.github.ksoichiro.android.observablescrollview.ObservableWebView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> </android.support.v4.widget.NestedScrollView> </android.support.v4.widget.SwipeRefreshLayout> </android.support.design.widget.CoordinatorLayout>
In this case the page is not scrolling. I have tried many variants. If in the behavior I put clean webview (without swiperefresh, nestedscrolling etc) it’s work correctly, but if I lock and unlock the screen – WebView swells up and on the bottom of page appears white empty place. I have been trying to solve this problem for several days now, but it doesn’t work. Please help make a stable solution to this problem. Thank you very much.
I tried this method: How to Hide ActionBar/Toolbar While Scrolling Down in Webview but if I lock and unlock the screen – WebView swells up and on the bottom of page appears white empty place
Advertisement
Answer
I created WebView with this features and it works perfect:
import android.content.Context; import android.support.v4.view.MotionEventCompat; import android.support.v4.view.NestedScrollingChild; import android.support.v4.view.NestedScrollingChildHelper; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.ViewGroup; import android.webkit.WebView; public class NestedWebView extends WebView implements NestedScrollingChild, Scrollable { private int mLastY; private final int[] mScrollOffset = new int[2]; private final int[] mScrollConsumed = new int[2]; private int mNestedOffsetY; private NestedScrollingChildHelper mChildHelper; private int mScrollY; private ScrollViewCallback callback; private boolean firstScroll = true; 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); } public void setOnScrollListener(ScrollViewCallback callback) { this.callback = callback; } @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 deltaY = mLastY - eventY; // NestedPreScroll if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) { deltaY -= mScrollConsumed[1]; mLastY = eventY - mScrollOffset[1]; event.offsetLocation(0, -mScrollOffset[1]); mNestedOffsetY += mScrollOffset[1]; } returnValue = super.onTouchEvent(event); // NestedScroll if (dispatchNestedScroll(0, mScrollOffset[1], 0, deltaY, mScrollOffset)) { event.offsetLocation(0, mScrollOffset[1]); mNestedOffsetY += mScrollOffset[1]; mLastY -= mScrollOffset[1]; } break; case MotionEvent.ACTION_DOWN: returnValue = super.onTouchEvent(event); if (firstScroll) { // dispatching first down scrolling properly by making sure that first deltaY will be -ve mLastY = eventY - 5; firstScroll = false; } else { mLastY = eventY; } // start NestedScroll startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL); break; default: returnValue = super.onTouchEvent(event); 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); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); mScrollY = t; dispatchOnScrollChanged(mScrollY); } private void dispatchOnScrollChanged(int scrollY) { if (callback != null) { callback.onScrollChanged(scrollY); } } // Scrollable implements @Override public void setScrollViewCallbacks(ObservableScrollViewCallbacks listener) { } @Override public void scrollVerticallyTo(int y) { } @Override public int getCurrentScrollY() { return mScrollY; } @Override public void setTouchInterceptionViewGroup(ViewGroup viewGroup) { } public interface ScrollViewCallback { void onScrollChanged(int scrollY); } }