package org.aisen.weibo.sina.support.utils;
import android.os.Build;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.AbsListView;
import com.melnykov.fab.ScrollDirectionListener;
import com.nineoldandroids.view.ViewHelper;
import com.nineoldandroids.view.ViewPropertyAnimator;
/**
* Created by wangdan on 16/2/2.
*/
public class FabAnimator {
private static final int TRANSLATE_DURATION_MILLIS = 300;
private int duration = TRANSLATE_DURATION_MILLIS;
private int scrollThreshold;
private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
private FabAnimator(View fabBtn, int scrollThreshold) {
this.fabBtn = fabBtn;
this.scrollThreshold = scrollThreshold;
}
public void setDuration(int duration) {
this.duration = duration;
}
public static FabAnimator create(View fabBtn, int scrollThreshold) {
return new FabAnimator(fabBtn, scrollThreshold);
}
private View fabBtn;
private boolean mVisible = true;
public void attachToListView(AbsListView listView,ScrollDirectionListener scrollDirectionListener,
AbsListView.OnScrollListener onScrollListener) {
AbsListViewScrollDetectorImpl scrollDetector = new AbsListViewScrollDetectorImpl();
scrollDetector.setScrollDirectionListener(scrollDirectionListener);
scrollDetector.setOnScrollListener(onScrollListener);
scrollDetector.setListView(listView);
scrollDetector.setScrollThreshold(scrollThreshold);
listView.setOnScrollListener(scrollDetector);
}
public void attachToRecyclerView(RecyclerView recyclerView,
ScrollDirectionListener scrollDirectionlistener,
RecyclerView.OnScrollListener onScrollListener) {
RecyclerViewScrollDetectorImpl scrollDetector = new RecyclerViewScrollDetectorImpl();
scrollDetector.setScrollDirectionListener(scrollDirectionlistener);
if (onScrollListener != null) {
scrollDetector.setOnScrollListener(onScrollListener);
}
scrollDetector.setScrollThreshold(scrollThreshold);
recyclerView.addOnScrollListener(scrollDetector);
}
private abstract class AbsListViewScrollDetector implements AbsListView.OnScrollListener {
private int mLastScrollY;
private int mPreviousFirstVisibleItem;
private AbsListView mListView;
private int mScrollThreshold;
abstract void onScrollUp();
abstract void onScrollDown();
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (totalItemCount == 0) return;
if (isSameRow(firstVisibleItem)) {
int newScrollY = getTopItemScrollY();
boolean isSignificantDelta = Math.abs(mLastScrollY - newScrollY) > mScrollThreshold;
if (isSignificantDelta) {
if (mLastScrollY > newScrollY) {
onScrollUp();
} else {
onScrollDown();
}
}
mLastScrollY = newScrollY;
} else {
if (firstVisibleItem > mPreviousFirstVisibleItem) {
onScrollUp();
} else {
onScrollDown();
}
mLastScrollY = getTopItemScrollY();
mPreviousFirstVisibleItem = firstVisibleItem;
}
}
public void setScrollThreshold(int scrollThreshold) {
mScrollThreshold = scrollThreshold;
}
public void setListView(AbsListView listView) {
mListView = listView;
}
private boolean isSameRow(int firstVisibleItem) {
return firstVisibleItem == mPreviousFirstVisibleItem;
}
private int getTopItemScrollY() {
if (mListView == null || mListView.getChildAt(0) == null) return 0;
View topChild = mListView.getChildAt(0);
return topChild.getTop();
}
}
private class AbsListViewScrollDetectorImpl extends AbsListViewScrollDetector {
private ScrollDirectionListener mScrollDirectionListener;
private AbsListView.OnScrollListener mOnScrollListener;
private void setScrollDirectionListener(ScrollDirectionListener scrollDirectionListener) {
mScrollDirectionListener = scrollDirectionListener;
}
public void setOnScrollListener(AbsListView.OnScrollListener onScrollListener) {
mOnScrollListener = onScrollListener;
}
@Override
public void onScrollDown() {
show();
if (mScrollDirectionListener != null) {
mScrollDirectionListener.onScrollDown();
}
}
@Override
public void onScrollUp() {
hide();
if (mScrollDirectionListener != null) {
mScrollDirectionListener.onScrollUp();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
super.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(view, scrollState);
}
super.onScrollStateChanged(view, scrollState);
}
}
public void show() {
show(true);
}
public void hide() {
hide(true);
}
public void show(boolean animate) {
toggle(true, animate, false);
}
public void hide(boolean animate) {
toggle(false, animate, false);
}
private void toggle(final boolean visible, final boolean animate, boolean force) {
if (mVisible != visible || force) {
mVisible = visible;
int height = fabBtn.getHeight();
if (height == 0 && !force) {
ViewTreeObserver vto = fabBtn.getViewTreeObserver();
if (vto.isAlive()) {
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
ViewTreeObserver currentVto = fabBtn.getViewTreeObserver();
if (currentVto.isAlive()) {
currentVto.removeOnPreDrawListener(this);
}
toggle(visible, animate, true);
return true;
}
});
return;
}
}
int translationY = visible ? 0 : height + getMarginBottom();
if (animate) {
ViewPropertyAnimator.animate(fabBtn).setInterpolator(mInterpolator)
.setDuration(TRANSLATE_DURATION_MILLIS)
.translationY(translationY);
} else {
ViewHelper.setTranslationY(fabBtn, translationY);
}
// On pre-Honeycomb a translated view is still clickable, so we need to disable clicks manually
if (!hasHoneycombApi()) {
fabBtn.setClickable(visible);
}
}
}
private int getMarginBottom() {
int marginBottom = 0;
final ViewGroup.LayoutParams layoutParams = fabBtn.getLayoutParams();
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
marginBottom = ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin;
}
return marginBottom;
}
private boolean hasHoneycombApi() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
}
abstract class RecyclerViewScrollDetector extends RecyclerView.OnScrollListener {
private int mScrollThreshold;
abstract void onScrollUp();
abstract void onScrollDown();
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
boolean isSignificantDelta = Math.abs(dy) > mScrollThreshold;
if (isSignificantDelta) {
if (dy > 0) {
onScrollUp();
} else {
onScrollDown();
}
}
}
public void setScrollThreshold(int scrollThreshold) {
mScrollThreshold = scrollThreshold;
}
}
private class RecyclerViewScrollDetectorImpl extends RecyclerViewScrollDetector {
private ScrollDirectionListener mScrollDirectionListener;
private RecyclerView.OnScrollListener mOnScrollListener;
private void setScrollDirectionListener(ScrollDirectionListener scrollDirectionListener) {
mScrollDirectionListener = scrollDirectionListener;
}
public void setOnScrollListener(RecyclerView.OnScrollListener onScrollListener) {
mOnScrollListener = onScrollListener;
}
@Override
public void onScrollDown() {
show();
if (mScrollDirectionListener != null) {
mScrollDirectionListener.onScrollDown();
}
}
@Override
public void onScrollUp() {
hide();
if (mScrollDirectionListener != null) {
mScrollDirectionListener.onScrollUp();
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (mOnScrollListener != null) {
mOnScrollListener.onScrolled(recyclerView, dx, dy);
}
super.onScrolled(recyclerView, dx, dy);
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(recyclerView, newState);
}
super.onScrollStateChanged(recyclerView, newState);
}
}
}