package io.codetail.utils; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewConfiguration; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import com.nineoldandroids.animation.ObjectAnimator; import com.nineoldandroids.view.ViewHelper; import com.nineoldandroids.view.ViewPropertyAnimator; import com.squareup.otto.Bus; import com.squareup.picasso.Picasso; import java.lang.ref.WeakReference; import javax.inject.Inject; import codetail.animation.ViewAnimationUtils; import codetail.utils.HideExtraOnScrollHelper; import codetail.utils.ResourceUtils; import io.codetail.Constants; import io.codetail.WatchMeApplication; public class ScrollManager extends RecyclerView.OnScrollListener{ public static class LoadMoreItems{} public final static int MIN_VISIBLE_ITEMS = 20 * 3; public final static int LOAD_IF_LESS_THAN = 5; final static Interpolator ACCELERATE = new AccelerateInterpolator(); final static Interpolator DECELERATE = new DecelerateInterpolator(); Bus mEventBus; @Inject Picasso mPicasso; WeakReference<View> mTargetToolbar; WeakReference<View> mTargetFab; HideExtraOnScrollHelper mScrollHelper; LoadMoreItems mMoreEvent; boolean isExtraObjectsOutside; boolean isScrollUpFloating; public ScrollManager(View target, View fab) { int minimumFlingVelocity = ViewConfiguration.get(target.getContext()) .getScaledMinimumFlingVelocity(); mScrollHelper = new HideExtraOnScrollHelper(minimumFlingVelocity); mTargetToolbar = new WeakReference<>(target); mTargetFab = new WeakReference<>(fab); mMoreEvent = new LoadMoreItems(); mEventBus = Constants.getEventBus(); } public void setEventBus(Bus bus) { mEventBus = bus; } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); switch (newState){ case RecyclerView.SCROLL_STATE_DRAGGING: mPicasso.pauseTag(WatchMeApplication.PICASSO_INSTANCE); break; case RecyclerView.SCROLL_STATE_IDLE: mPicasso.resumeTag(WatchMeApplication.PICASSO_INSTANCE); break; } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); final View target = mTargetToolbar.get(); final View fab = mTargetFab.get(); if(target == null || fab == null) { return; } boolean needsToHideExtraObjects = mScrollHelper.isObjectsShouldBeOutside(dy); if(!isToolbarVisible() && !needsToHideExtraObjects){ show(target); isExtraObjectsOutside = false; }else if(isToolbarVisible() && needsToHideExtraObjects){ hide(target, -target.getHeight()); isExtraObjectsOutside = true; } toggleScrollUp(recyclerView); loadMoreItemsIfNecessary(recyclerView); } public boolean isUserNeedInFastScrollUp(RecyclerView view){ LinearLayoutManager manager = (LinearLayoutManager) view.getLayoutManager(); return manager.findFirstCompletelyVisibleItemPosition() >= MIN_VISIBLE_ITEMS; } public void toggleScrollUp(RecyclerView view){ boolean showFab = isUserNeedInFastScrollUp(view); if(showFab && !isFabVisible()){ isScrollUpFloating = true; showFab(); }else if(!showFab && isFabVisible()){ isScrollUpFloating = false; hideFab(); } } public void showFab(){ View fab = mTargetFab.get(); fab.setVisibility(View.VISIBLE); ViewHelper.setTranslationY(fab, fab.getHeight() + ResourceUtils.dp(16)); ViewPropertyAnimator .animate(fab) .setInterpolator(ViewAnimationUtils.ACCELERATE_DECELERATE) .setDuration(350) .translationY(0) .start(); } public void showToolbar(){ show(mTargetToolbar.get()); } public void hideFab(){ View fab = mTargetFab.get(); ViewPropertyAnimator .animate(fab) .setInterpolator(ViewAnimationUtils.ACCELERATE_DECELERATE) .setDuration(350) .translationY(fab.getHeight() + ResourceUtils.dp(16)) .start(); } public void loadMoreItemsIfNecessary(RecyclerView recyclerView){ LinearLayoutManager layout = (LinearLayoutManager) recyclerView.getLayoutManager(); int visibleItemCount = recyclerView.getChildCount(); int totalItemCount = layout.getItemCount(); int firstVisibleItem = layout.findFirstVisibleItemPosition(); if ((totalItemCount - (firstVisibleItem + visibleItemCount)) <= LOAD_IF_LESS_THAN){ mEventBus.post(mMoreEvent); } } public boolean isToolbarVisible(){ return !isExtraObjectsOutside; } public boolean isFabVisible(){ return isScrollUpFloating; } public void hide(final View target, float distance){ ObjectAnimator animator = ObjectAnimator.ofFloat(target, "translationY", ViewHelper.getTranslationY(target), distance); animator.setAutoCancel(true); animator.setInterpolator(DECELERATE); animator.start(); } public void show(final View target){ ObjectAnimator animator = ObjectAnimator.ofFloat(target, "translationY", ViewHelper.getTranslationY(target), 0f); animator.setAutoCancel(true); animator.setInterpolator(ACCELERATE); animator.start(); } }