package tellh.com.gitclub.presentation.widget; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.content.res.TypedArray; import android.support.design.widget.CoordinatorLayout; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.View; import android.view.ViewConfiguration; import android.view.animation.DecelerateInterpolator; import tellh.com.gitclub.R; import tellh.com.gitclub.presentation.contract.bus.RxBusPostman; public class QuickReturnTopBehavior extends CoordinatorLayout.Behavior<View> { private static final int DEFAULT = 0; private static final int OFFSET = 1; private final int mTouchSlop; private boolean once; private int distanceToHide; private boolean animationTime; private int mOffset; private boolean mControlsVisible; private int style; public QuickReturnTopBehavior(Context context, AttributeSet attrs) { super(context, attrs); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); init(context, attrs); } private void init(Context context, AttributeSet attrs) { final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.QuickReturnBehavior); style = typedArray.getInt(R.styleable.QuickReturnBehavior_quick_return_style, 0); typedArray.recycle(); } @Override public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) { if (!once) { distanceToHide = child.getBottom(); once = true; } return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL; } //handle sliding event @Override public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { if (animationTime) return; switch (style) { case DEFAULT: if (dyConsumed > 0 && dyConsumed > mTouchSlop) {//手指上滑 hide(child); } else if (dyConsumed < 0 && dyConsumed < 2 * mTouchSlop) {//手指下滑 show(child); } break; case OFFSET: clipOffset(); move(child, mOffset); if ((mOffset < distanceToHide && dyConsumed > 0) || (mOffset > 0 && dyConsumed < 0)) { mOffset += dyConsumed; } break; default: style = DEFAULT; break; } } @Override public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) { if (style == OFFSET) { if (mControlsVisible) { if (mOffset > mTouchSlop) setInvisible(child); else setVisible(child); } else { if ((distanceToHide - mOffset) > mTouchSlop) setVisible(child); } } } private void clipOffset() { if (mOffset > distanceToHide) { mOffset = distanceToHide; } else if (mOffset < 0) { mOffset = 0; } } private void setVisible(View view) { if (mOffset > 0) { show(view); mOffset = 0; } mControlsVisible = true; } private void setInvisible(View view) { if (mOffset < distanceToHide) { hide(view); mOffset = distanceToHide; } mControlsVisible = false; } private void show(View view) { RxBusPostman.postQuickReturnEvent(true); if (view != null) { view.animate() .translationY(0) .setInterpolator(new DecelerateInterpolator(2)) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { animationTime = false; } @Override public void onAnimationStart(Animator animation) { animationTime = true; } }) .start(); } } private void hide(View view) { RxBusPostman.postQuickReturnEvent(false); if (view != null) { view.animate() .translationY(-distanceToHide) .setInterpolator(new DecelerateInterpolator(2)) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { animationTime = true; } @Override public void onAnimationEnd(Animator animation) { animationTime = false; } }) .start(); } } private void move(View View, int distance) { View.setTranslationY(-distance); } }