package org.wikipedia.page; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.Gravity; import android.view.View; import org.wikipedia.views.ObservableWebView; import org.wikipedia.views.ViewAnimations; public abstract class ViewHideHandler implements ObservableWebView.OnScrollChangeListener, ObservableWebView.OnUpOrCancelMotionEventListener, ObservableWebView.OnDownMotionEventListener, ObservableWebView.OnClickListener{ @NonNull private final View hideableView; @Nullable private ObservableWebView webView; private final int gravity; public ViewHideHandler(@NonNull View hideableView, int gravity) { this.hideableView = hideableView; this.gravity = gravity; } /** * Update the WebView based on whose scroll position the search bar will hide itself. * @param webView The WebView against which scrolling will be tracked. */ public void setScrollView(@Nullable ObservableWebView webView) { this.webView = webView; if (webView != null) { webView.addOnScrollChangeListener(this); webView.addOnDownMotionEventListener(this); webView.addOnUpOrCancelMotionEventListener(this); webView.addOnClickListener(this); } } /** * Force an update of the appearance of the search bar. Usually it is updated automatically * when the associated WebView is scrolled, but this function may be used to manually refresh * the appearance of the search bar, e.g. when the WebView is first shown. */ public void update() { if (webView == null) { return; } onScrollChanged(webView.getScrollY(), webView.getScrollY(), false); } @Override public void onScrollChanged(int oldScrollY, int scrollY, boolean isHumanScroll) { if (webView == null) { return; } onScrolled(oldScrollY, scrollY); if (gravity == Gravity.TOP && scrollY <= webView.getHeight()) { // For the first screenful, ensure it's always shown ensureDisplayed(); return; } int animMargin = 0; int scrollDelta = scrollY - oldScrollY; if (!isHumanScroll) { animMargin = 0; } else if (gravity == Gravity.BOTTOM) { if (oldScrollY < scrollY) { // Scroll down animMargin = Math.min(hideableView.getHeight(), (int) hideableView.getTranslationY() + scrollDelta); } else { // Scroll up animMargin = Math.max(0, (int) hideableView.getTranslationY() + scrollDelta); } } else if (gravity == Gravity.TOP) { if (oldScrollY > scrollY) { // scroll up animMargin = Math.min(0, (int) hideableView.getTranslationY() - scrollDelta); } else { // scroll down animMargin = Math.max(-hideableView.getHeight(), (int) hideableView.getTranslationY() - scrollDelta); } } hideableView.setTranslationY(animMargin); } @Override public void onUpOrCancelMotionEvent() { int transY = (int) hideableView.getTranslationY(); int height = hideableView.getHeight(); if (gravity == Gravity.BOTTOM && transY != 0 && transY < height) { if (transY > height / 2) { ensureHidden(); } else { ensureDisplayed(); } } else if (gravity == Gravity.TOP && transY != 0 && transY > -height) { if (transY > -height / 2) { ensureDisplayed(); } else { ensureHidden(); } } } @Override public void onDownMotionEvent() { // Don't do anything for now } @Override public boolean onClick(float x, float y) { ensureDisplayed(); return false; } protected abstract void onScrolled(int oldScrollY, int scrollY); private void ensureDisplayed() { ViewAnimations.ensureTranslationY(hideableView, 0); } private void ensureHidden() { ViewAnimations.ensureTranslationY(hideableView, gravity == Gravity.BOTTOM ? hideableView.getHeight() : -hideableView.getHeight()); } }