package com.example.administrator.cookman.ui.component.twinklingrefreshlayout;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.view.animation.DecelerateInterpolator;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
/**
* Created by lcodecore on 2016/11/26.
*/
public class AnimProcessor {
private TwinklingRefreshLayout.CoProcessor cp;
private static final float animFraction = 1f;
//动画的变化率
private DecelerateInterpolator decelerateInterpolator;
public AnimProcessor(TwinklingRefreshLayout.CoProcessor coProcessor) {
this.cp = coProcessor;
decelerateInterpolator = new DecelerateInterpolator(8);
}
public void init() {
}
public void scrollHeadByMove(float moveY) {
float offsetY = decelerateInterpolator.getInterpolation(moveY / cp.getMaxHeadHeight() / 2) * moveY / 2;
if (cp.getHeader().getVisibility() != VISIBLE) cp.getHeader().setVisibility(VISIBLE);
if (cp.isPureScrollModeOn()) cp.getHeader().setVisibility(GONE);
cp.getHeader().getLayoutParams().height = (int) Math.abs(offsetY);
cp.getHeader().requestLayout();
if (!cp.isOpenFloatRefresh()) {
cp.getContent().setTranslationY(offsetY);
translateExHead((int) offsetY);
}
cp.onPullingDown(offsetY);
}
public void scrollBottomByMove(float moveY) {
float offsetY = decelerateInterpolator.getInterpolation(moveY / cp.getBottomHeight() / 2) * moveY / 2;
if (cp.getFooter().getVisibility() != VISIBLE) cp.getFooter().setVisibility(VISIBLE);
if (cp.isPureScrollModeOn()) cp.getFooter().setVisibility(GONE);
cp.getFooter().getLayoutParams().height = (int) Math.abs(offsetY);
cp.getFooter().requestLayout();
cp.getContent().setTranslationY(-offsetY);
cp.onPullingUp(-offsetY);
}
public void dealPullDownRelease() {
if (!cp.isPureScrollModeOn() && getVisibleHeadHeight() >= cp.getHeadHeight() - cp.getTouchSlop()) {
animHeadToRefresh();
} else {
animHeadBack();
}
}
public void dealPullUpRelease() {
if (!cp.isPureScrollModeOn() && getVisibleFootHeight() >= cp.getBottomHeight() - cp.getTouchSlop()) {
animBottomToLoad();
} else {
animBottomBack();
}
}
private int getVisibleHeadHeight() {
return cp.getHeader().getLayoutParams().height;
}
private int getVisibleFootHeight() {
return cp.getFooter().getLayoutParams().height;
}
private boolean isAnimHeadToRefresh = false;
/**
* 1.满足进入刷新的条件或者主动刷新时,把Head位移到刷新位置(当前位置 ~ HeadHeight)
*/
public void animHeadToRefresh() {
isAnimHeadToRefresh = true;
animLayoutByTime(getVisibleHeadHeight(), cp.getHeadHeight(), animHeadUpListener, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isAnimHeadToRefresh = false;
cp.setRefreshing(true);
cp.onRefresh();
}
});
}
private boolean isAnimHeadBack = false;
/**
* 2.动画结束或不满足进入刷新状态的条件,收起头部(当前位置 ~ 0)
*/
public void animHeadBack() {
isAnimHeadBack = true;
animLayoutByTime(getVisibleHeadHeight(), 0, animHeadUpListener, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isAnimHeadBack = false;
}
});
}
private boolean isAnimBottomToLoad = false;
/**
* 3.满足进入加载更多的条件或者主动加载更多时,把Footer移到加载更多位置(当前位置 ~ BottomHeight)
*/
public void animBottomToLoad() {
isAnimBottomToLoad = true;
animLayoutByTime(getVisibleFootHeight(), cp.getBottomHeight(), animBottomUpListener, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isAnimBottomToLoad = false;
cp.setLoadingMore(true);
cp.onLoadMore();
}
});
}
private boolean isAnimBottomBack = false;
/**
* 4.加载更多完成或者不满足进入加载更多模式的条件时,收起尾部(当前位置 ~ 0)
*/
public void animBottomBack() {
isAnimBottomBack = true;
animLayoutByTime(getVisibleFootHeight(), 0, animBottomUpListener, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isAnimBottomBack = false;
}
});
}
private boolean isAnimHeadHide = false;
/**
* 5.当刷新处于可见状态,向上滑动屏幕时,隐藏刷新控件
*
* @param vy 手指向上滑动速度
*/
public void animHeadHideByVy(int vy) {
isAnimHeadHide = true;
cp.onRefreshCanceled();
vy = Math.abs(vy);
if (vy < 5000) vy = 8000;
animLayoutByTime(getVisibleHeadHeight(), 0, 5 * Math.abs(getVisibleHeadHeight() * 1000 / vy), animHeadUpListener, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isAnimHeadHide = false;
cp.resetHeaderView();
}
});
}
private boolean isAnimBottomHide = false;
/**
* 6.当加载更多处于可见状态时,向下滑动屏幕,隐藏加载更多控件
*
* @param vy 手指向下滑动的速度
*/
public void animBottomHideByVy(int vy) {
isAnimBottomHide = true;
cp.onLoadmoreCanceled();
vy = Math.abs(vy);
if (vy < 5000) vy = 8000;
animLayoutByTime(getVisibleFootHeight(), 0, 5 * getVisibleFootHeight() * 1000 / vy, animBottomUpListener, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isAnimBottomHide = false;
cp.resetBottomView();
}
});
}
private boolean isAnimOsTop = false;
/**
* 7.执行顶部越界 To executive cross-border springback at the top.
* 越界高度height ∝ vy/computeTimes,此处采用的模型是 height=A*(vy + B)/computeTimes
*
* @param vy 满足越界条件的手指滑动速度 the finger sliding speed on the screen.
* @param computeTimes 从满足条件到滚动到顶部总共计算的次数 Calculation times from sliding to top.
*/
public void animOverScrollTop(float vy, int computeTimes) {
if (cp.isOsTopLocked()) return;
cp.lockOsTop();
isAnimOsTop = true;
cp.setStatePTD();
int oh = (int) Math.abs(vy / computeTimes / 2);
final int overHeight = oh > cp.getOsHeight() ? cp.getOsHeight() : oh;
final int time = overHeight <= 50 ? 115 : (int) (0.3 * overHeight + 100);
animLayoutByTime(0, overHeight, time, overScrollTopUpListener, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
animLayoutByTime(overHeight, 0, 2 * time, overScrollTopUpListener, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isAnimOsTop = false;
cp.releaseOsTopLock();
}
});
}
});
}
private boolean isAnimOsBottom = false;
/**
* 8.执行底部越界
*
* @param vy 满足越界条件的手指滑动速度
* @param computeTimes 从满足条件到滚动到顶部总共计算的次数
*/
public void animOverScrollBottom(float vy, int computeTimes) {
if (cp.isOsBottomLocked()) return;
cp.setStatePBU();
int oh = (int) Math.abs(vy / computeTimes / 2);
final int overHeight = oh > cp.getOsHeight() ? cp.getOsHeight() : oh;
final int time = overHeight <= 50 ? 115 : (int) (0.3 * overHeight + 100);
if (cp.autoLoadMore()) {
cp.startLoadMore();
} else {
cp.lockOsBottom();
isAnimOsBottom = true;
animLayoutByTime(0, overHeight, time, overScrollBottomUpListener, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
animLayoutByTime(overHeight, 0, 2 * time, overScrollBottomUpListener, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isAnimOsBottom = false;
cp.releaseOsBottomLock();
}
});
}
});
}
}
private AnimatorUpdateListener animHeadUpListener = new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int height = (int) animation.getAnimatedValue();
cp.getHeader().getLayoutParams().height = height;
cp.getHeader().requestLayout();
if (!cp.isOpenFloatRefresh()) {
cp.getContent().setTranslationY(height);
translateExHead(height);
}
cp.onPullDownReleasing(height);
}
};
private AnimatorUpdateListener animBottomUpListener = new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int height = (int) animation.getAnimatedValue();
cp.getFooter().getLayoutParams().height = height;
cp.getFooter().requestLayout();
cp.getContent().setTranslationY(-height);
cp.onPullUpReleasing(height);
}
};
private AnimatorUpdateListener overScrollTopUpListener = new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int height = (int) animation.getAnimatedValue();
if (cp.isOverScrollTopShow()) {
cp.getHeader().getLayoutParams().height = height;
cp.getHeader().requestLayout();
} else cp.getHeader().setVisibility(GONE);
cp.getContent().setTranslationY(height);
translateExHead(height);
cp.onPullDownReleasing(height);
}
};
private AnimatorUpdateListener overScrollBottomUpListener = new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int height = (int) animation.getAnimatedValue();
if (cp.isOverScrollBottomShow()) {
cp.getFooter().getLayoutParams().height = height;
cp.getFooter().requestLayout();
} else cp.getFooter().setVisibility(GONE);
cp.getContent().setTranslationY(-height);
cp.onPullUpReleasing(height);
}
};
public void onScrolled(int distanceY) {
//TODO 支持正常模式的Header to support the normal-mode ex-header.
}
private void translateExHead(int offsetY) {
if (!cp.isExHeadLocked()) cp.getExHead().setTranslationY(offsetY);
}
public void animLayoutByTime(int start, int end, long time, AnimatorUpdateListener listener, AnimatorListener animatorListener) {
ValueAnimator va = ValueAnimator.ofInt(start, end);
va.setInterpolator(new DecelerateInterpolator());
va.addUpdateListener(listener);
va.addListener(animatorListener);
va.setDuration(time);
va.start();
}
public void animLayoutByTime(int start, int end, long time, AnimatorUpdateListener listener) {
ValueAnimator va = ValueAnimator.ofInt(start, end);
va.setInterpolator(new DecelerateInterpolator());
va.addUpdateListener(listener);
va.setDuration(time);
va.start();
}
public void animLayoutByTime(int start, int end, AnimatorUpdateListener listener, AnimatorListener animatorListener) {
ValueAnimator va = ValueAnimator.ofInt(start, end);
va.setInterpolator(new DecelerateInterpolator());
va.addUpdateListener(listener);
va.addListener(animatorListener);
va.setDuration((int) (Math.abs(start - end) * animFraction));
va.start();
}
}