package com.wenchao.cardstack;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import com.wenchao.animation.RelativeLayoutParamsEvaluator;
import java.util.ArrayList;
import java.util.HashMap;
import static com.wenchao.cardstack.CardUtils.cloneParams;
import static com.wenchao.cardstack.CardUtils.getMoveParams;
import static com.wenchao.cardstack.CardUtils.move;
import static com.wenchao.cardstack.CardUtils.scale;
public class CardAnimator {
private static final String DEBUG_TAG = "CardAnimator";
public static final int TOP = 48;
public static final int BOTTOM = 80;
private static final int REMOTE_DISTANCE = 1000;
private int mBackgroundColor;
public ArrayList<View> mCardCollection;
private float mRotation;
private HashMap<View, RelativeLayout.LayoutParams> mLayoutsMap;
private RelativeLayout.LayoutParams[] mRemoteLayouts = new RelativeLayout.LayoutParams[4];
private RelativeLayout.LayoutParams baseLayout;
private int mStackMargin;
private int mGravity = BOTTOM;
private boolean mEnableRotation; // 是否允许旋转
public CardAnimator(ArrayList<View> viewCollection, int backgroundColor, int margin) {
mCardCollection = viewCollection;
mBackgroundColor = backgroundColor;
mStackMargin = margin;
setup();
}
private void setup() {
mLayoutsMap = new HashMap<View, RelativeLayout.LayoutParams>();
for (View v : mCardCollection) {
//setup basic layout
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) v.getLayoutParams();
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
params.width = LayoutParams.MATCH_PARENT;
params.height = LayoutParams.WRAP_CONTENT;
if (mBackgroundColor != -1) {
v.setBackgroundColor(mBackgroundColor);
}
v.setLayoutParams(params);
}
baseLayout = (RelativeLayout.LayoutParams) mCardCollection.get(0).getLayoutParams();
baseLayout = cloneParams(baseLayout);
}
public void initLayout() {
int size = mCardCollection.size();
for (View v : mCardCollection) {
int index = mCardCollection.indexOf(v);
if (index != 0) {
index -= 1;
}
LayoutParams params = cloneParams(baseLayout);
v.setLayoutParams(params);
scale(v, -(size - index - 1) * 5, mGravity);
int margin = index * mStackMargin;
move(v, mGravity == TOP ? -margin : margin, 0);
v.setRotation(0);
RelativeLayout.LayoutParams paramsCopy =
cloneParams((RelativeLayout.LayoutParams) v.getLayoutParams());
mLayoutsMap.put(v, paramsCopy);
}
setupRemotes();
}
/**
* 设置方向,支持上、下。
* 设置后调用{@link #initLayout()} 来重新初始化布局
*
* @param gravity {@link #TOP} 向上 {@link #BOTTOM} 向下,默认值
*/
public void setGravity(int gravity) {
mGravity = gravity;
}
private void setupRemotes() {
View topView = getTopView();
mRemoteLayouts[0] = getMoveParams(topView, REMOTE_DISTANCE, -REMOTE_DISTANCE);
mRemoteLayouts[1] = getMoveParams(topView, REMOTE_DISTANCE, REMOTE_DISTANCE);
mRemoteLayouts[2] = getMoveParams(topView, -REMOTE_DISTANCE, -REMOTE_DISTANCE);
mRemoteLayouts[3] = getMoveParams(topView, -REMOTE_DISTANCE, REMOTE_DISTANCE);
}
private View getTopView() {
return mCardCollection.get(mCardCollection.size() - 1);
}
private void moveToBack(View child) {
final ViewGroup parent = (ViewGroup) child.getParent();
if (null != parent) {
parent.removeView(child);
parent.addView(child, 0); // 移到最后一个
}
}
// 卡片排序,抽出一个,底部上来一个
private void reorder() {
View temp = getTopView();
//RelativeLayout.LayoutParams tempLp = mLayoutsMap.get(mCardCollection.get(0));
//mLayoutsMap.put(temp,tempLp);
moveToBack(temp);
for (int i = (mCardCollection.size() - 1); i > 0; i--) {
//View next = mCardCollection.get(i);
//RelativeLayout.LayoutParams lp = mLayoutsMap.get(next);
//mLayoutsMap.remove(next);
View current = mCardCollection.get(i - 1);
//current replace next
mCardCollection.set(i, current);
//mLayoutsMap.put(current,lp);
}
mCardCollection.set(0, temp);
}
// 销毁卡片
public void discard(int direction, final AnimatorListener al) {
AnimatorSet as = new AnimatorSet();
ArrayList<Animator> aCollection = new ArrayList<Animator>();
final View topView = getTopView();
RelativeLayout.LayoutParams topParams = (RelativeLayout.LayoutParams) topView.getLayoutParams();
RelativeLayout.LayoutParams layout = cloneParams(topParams);
ValueAnimator discardAnim = ValueAnimator.ofObject(new RelativeLayoutParamsEvaluator(), layout, mRemoteLayouts[direction]);
discardAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator value) {
topView.setLayoutParams((LayoutParams) value.getAnimatedValue());
}
});
discardAnim.setDuration(250);
aCollection.add(discardAnim);
for (int i = 0; i < mCardCollection.size(); i++) {
final View v = mCardCollection.get(i);
if (v == topView) continue;
final View nv = mCardCollection.get(i + 1);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
RelativeLayout.LayoutParams endLayout = cloneParams(layoutParams);
ValueAnimator layoutAnim = ValueAnimator.ofObject(new RelativeLayoutParamsEvaluator(), endLayout, mLayoutsMap.get(nv));
layoutAnim.setDuration(250);
layoutAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator value) {
v.setLayoutParams((LayoutParams) value.getAnimatedValue());
}
});
aCollection.add(layoutAnim);
}
as.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
reorder();
if (al != null) {
al.onAnimationEnd(animation);
}
mLayoutsMap = new HashMap<View, RelativeLayout.LayoutParams>();
for (View v : mCardCollection) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) v.getLayoutParams();
RelativeLayout.LayoutParams paramsCopy = cloneParams(params);
mLayoutsMap.put(v, paramsCopy);
}
}
});
as.playTogether(aCollection);
as.start();
}
/**
* 还原卡片位置
*/
public void reverse(MotionEvent e1, MotionEvent e2) {
final View topView = getTopView();
ValueAnimator rotationAnim = ValueAnimator.ofFloat(mRotation, 0f);
rotationAnim.setDuration(250);
rotationAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator v) {
topView.setRotation(((Float) (v.getAnimatedValue())).floatValue());
}
});
rotationAnim.start();
for (final View v : mCardCollection) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
RelativeLayout.LayoutParams endLayout = cloneParams(layoutParams);
ValueAnimator layoutAnim = ValueAnimator.ofObject(new RelativeLayoutParamsEvaluator(), endLayout, mLayoutsMap.get(v));
layoutAnim.setDuration(100);
layoutAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator value) {
v.setLayoutParams((LayoutParams) value.getAnimatedValue());
}
});
layoutAnim.start();
}
}
public void drag(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
View topView = getTopView();
int x_diff = (int) ((e2.getRawX() - e1.getRawX()));
int y_diff = (int) ((e2.getRawY() - e1.getRawY()));
float rotation_coefficient = 20f;
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) topView.getLayoutParams();
RelativeLayout.LayoutParams topViewLayouts = mLayoutsMap.get(topView);
layoutParams.leftMargin = topViewLayouts.leftMargin + x_diff;
layoutParams.rightMargin = topViewLayouts.rightMargin - x_diff;
layoutParams.topMargin = topViewLayouts.topMargin + y_diff;
layoutParams.bottomMargin = topViewLayouts.bottomMargin - y_diff;
if (mEnableRotation) {
mRotation = (x_diff / rotation_coefficient);
topView.setRotation(mRotation);
topView.setLayoutParams(layoutParams);
}
//animate secondary views.
for (View v : mCardCollection) {
int index = mCardCollection.indexOf(v);
if (v != getTopView() && index != 0) {
LayoutParams l = CardUtils.scaleFrom(v, mLayoutsMap.get(v), (int) (Math.abs(x_diff) * 0.05), mGravity);
CardUtils.moveFrom(v, l, 0, (int) (Math.abs(x_diff) * index * 0.05), mGravity);
}
}
}
public void setStackMargin(int margin) {
mStackMargin = margin;
}
public boolean isEnableRotation() {
return mEnableRotation;
}
public void setEnableRotation(boolean enableRotation) {
mEnableRotation = enableRotation;
}
}