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.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import tellh.com.gitclub.R;
import tellh.com.gitclub.common.utils.Utils;
import tellh.com.gitclub.presentation.contract.bus.RxBusPostman;
public class QuickReturnBottomBehavior extends CoordinatorLayout.Behavior<View> {
private int mTouchSlop;
private boolean once;
private int distanceToHide;
private boolean animationTime;
private static final int TRANSLATE = 0;
private static final int TRANSLATE_OFFSET = 1;
private static final int SCALE = 2;
private static final int SCALE_OFFSET = 3;
private int style;
private int mOffset;
private boolean mControlsVisible;
public QuickReturnBottomBehavior(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) {
int screenHeight = Utils.getScreenHeight();
int top = child.getTop();
distanceToHide = screenHeight - top;
once = true;
}
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
//处理滑动事件
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
// Log.d("TAG","dxConsumed = [" + dxConsumed + "], dyConsumed = [" + dyConsumed + "], dxUnconsumed = [" + dxUnconsumed + "], dyUnconsumed = [" + dyUnconsumed + "]");
if (animationTime)
return;
switch (style) {
case TRANSLATE:
if (dyConsumed > 0 && dyConsumed > mTouchSlop) {//手指上滑
hide(child);
} else if (dyConsumed < 0 && dyConsumed < 2 * mTouchSlop) {//手指下滑
show(child);
}
break;
case SCALE_OFFSET:
case TRANSLATE_OFFSET:
clipOffset();
move(mOffset, child);
if ((mOffset < distanceToHide && dyConsumed > 0) || (mOffset > 0 && dyConsumed < 0)) {
mOffset += dyConsumed;
}
break;
case SCALE:
if (dyConsumed > 0 && dyConsumed > mTouchSlop) {//手指上滑
toggleScale(child, false);
} else if (dyConsumed < 0 && dyConsumed < 2 * mTouchSlop) {//手指下滑
toggleScale(child, true);
}
break;
default:
style = TRANSLATE;
break;
}
}
private void toggleScale(View child, final boolean visible) {
float scaleX = !visible ? 0 : 1;
float scaleY = !visible ? 0 : 1;
child.animate().setInterpolator(new DecelerateInterpolator())
.setDuration(300)
.scaleX(scaleX)
.scaleY(scaleY)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
animationTime = true;
}
@Override
public void onAnimationEnd(Animator animation) {
if (!visible) {
mOffset = distanceToHide;
mControlsVisible = false;
} else {
mOffset = 0;
mControlsVisible = true;
}
animationTime = false;
}
}).start();
}
private void toggleScale(View child) {
float scaleX = mControlsVisible ? 0 : 1;
float scaleY = mControlsVisible ? 0 : 1;
child.animate().setInterpolator(new DecelerateInterpolator())
.setDuration(300)
.scaleX(scaleX)
.scaleY(scaleY)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
animationTime = true;
}
@Override
public void onAnimationEnd(Animator animation) {
if (mControlsVisible) {
mOffset = distanceToHide;
mControlsVisible = false;
} else {
mOffset = 0;
mControlsVisible = true;
}
animationTime = false;
}
}).start();
}
@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {
if (style == TRANSLATE_OFFSET) {
if (mControlsVisible) {
if (mOffset > mTouchSlop)
setInvisible(child);
else
setVisible(child);
} else {
if ((distanceToHide - mOffset) > mTouchSlop)
setVisible(child);
}
} else if (style == SCALE_OFFSET) {
if (mControlsVisible) {
if (mOffset > mTouchSlop)
toggleScale(child);
else
toggleScale(child, true);
} else {
if ((distanceToHide - mOffset) > mTouchSlop)
toggleScale(child);
}
}
}
private void setVisible(View view) {
show(view);
mOffset = 0;
mControlsVisible = true;
}
private void setInvisible(View view) {
hide(view);
mOffset = distanceToHide;
mControlsVisible = false;
}
private void clipOffset() {
if (mOffset > distanceToHide) {
mOffset = distanceToHide;
} else if (mOffset < 0) {
mOffset = 0;
}
}
protected 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) {
super.onAnimationEnd(animation);
animationTime = false;
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
animationTime = true;
}
})
.start();
}
}
protected void hide(View view) {
RxBusPostman.postQuickReturnEvent(false);
if (view != null) {
view.animate()
.translationY(distanceToHide)
.setInterpolator(new AccelerateInterpolator(2))
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
animationTime = false;
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
animationTime = true;
}
})
.start();
}
}
public void move(int distance, View view) {
if (style == SCALE_OFFSET) {
float offset = mOffset == 0 ? 1.0f : 1 - (float) mOffset / (float) distanceToHide;
ViewCompat.setScaleY(view, offset);
ViewCompat.setScaleX(view, offset);
} else {
ViewCompat.setTranslationY(view, distance);
}
}
}