@@ -0,0 +1,409 @@
package com.yydcdut.sdlv;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.FrameLayout;
import android.widget.Scroller;

/**
* Created by yuyidong on 15/9/24.
* todo fingerLeftAndRightMove()这个方法是可以优化的
*/
class ItemMainLayout2 extends FrameLayout {
private static final int INTENTION_LEFT_OPEN = 1;
private static final int INTENTION_LEFT_CLOSE = 2;
private static final int INTENTION_LEFT_ALREADY_OPEN = 3;
private static final int INTENTION_RIGHT_OPEN = -1;
private static final int INTENTION_RIGHT_CLOSE = -2;
private static final int INTENTION_RIGHT_ALREADY_OPEN = -3;
private static final int INTENTION_SCROLL_BACK = -4;
private static final int INTENTION_ZERO = 0;
private int mIntention = INTENTION_ZERO;

private static final int SCROLL_STATE_OPEN = 1;
private static final int SCROLL_STATE_CLOSE = 0;
private int mScrollState = SCROLL_STATE_CLOSE;
/* 时间 */
private static final int SCROLL_TIME = 500;//500ms
private static final int SCROLL_BACK = 250;//250MS
private static final int SCROLL_QUICK_TIME = 200;//200ms
private static final int SCROLL_DELETE_TIME = 300;//300ms
/* 控件高度 */
private int mHeight;
/* 子控件中button的总宽度 */
private int mBtnLeftTotalWidth;
private int mBtnRightTotalWidth;
/* 子view */
private ItemBackGroundLayout mItemLeftBackGroundLayout;
private ItemBackGroundLayout mItemRightBackGroundLayout;
private ItemCustomLayout mItemCustomLayout;
/* Scroller */
private Scroller mScroller;
/* 控件是否滑动 */
private boolean mIsMoving = false;
/* 是不是要滑过(over) */
private boolean mWannaOver = true;
/* 坐标 */
private float mXDown;
private float mYDown;
/* X方向滑动距离 */
private float mXScrollDistance;
/* 滑动的监听器 */
private OnItemSlideListenerProxy mOnItemSlideListenerProxy;

public ItemMainLayout2(Context context) {
this(context, null);
}

public ItemMainLayout2(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public ItemMainLayout2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mScroller = new Scroller(context);
mItemRightBackGroundLayout = new ItemBackGroundLayout(context);
addView(mItemRightBackGroundLayout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
mItemLeftBackGroundLayout = new ItemBackGroundLayout(context);
addView(mItemLeftBackGroundLayout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
mItemCustomLayout = new ItemCustomLayout(context);
addView(mItemCustomLayout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}

/**
* 得到CustomView
*
* @return
*/
public ItemCustomLayout getItemCustomLayout() {
return mItemCustomLayout;
}

/**
* 得到左边的背景View
*
* @return
*/
public ItemBackGroundLayout getItemLeftBackGroundLayout() {
return mItemLeftBackGroundLayout;
}

/**
* 得到右边的背景View
*
* @return
*/
public ItemBackGroundLayout getItemRightBackGroundLayout() {
return mItemRightBackGroundLayout;
}

/**
* @param height
* @param btnLeftTotalWidth
* @param btnRightTotalWidth
* @param wannaOver
*/
public void setParams(int height, int btnLeftTotalWidth, int btnRightTotalWidth, boolean wannaOver) {
mHeight = height;
mBtnLeftTotalWidth = btnLeftTotalWidth;
mBtnRightTotalWidth = btnRightTotalWidth;
mWannaOver = wannaOver;
requestLayout();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mHeight);
for (int i = 0; i < getChildCount(); i++) {
measureChild(getChildAt(i), widthMeasureSpec, MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY));
}
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
getParent().requestDisallowInterceptTouchEvent(false);
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mXDown = ev.getX();
mYDown = ev.getY();
//控件初始距离
mXScrollDistance = mItemCustomLayout.getScrollX();
//是否有要scroll的动向,目前没有
mIsMoving = false;
break;
case MotionEvent.ACTION_MOVE:
if (fingerNotMove(ev) && !mIsMoving) {//手指的范围在50以内
//执行ListView的手势操作
getParent().requestDisallowInterceptTouchEvent(false);
} else if (fingerLeftAndRightMove(ev) || mIsMoving) {//上下范围在50,主要检测左右滑动
//是否有要scroll的动向
mIsMoving = true;
//执行控件的手势操作
getParent().requestDisallowInterceptTouchEvent(true);
float moveDistance = ev.getX() - mXDown;//这个往右是正,往左是负
//判断意图
if (moveDistance > 0) {//往右
if (mXScrollDistance == 0) {//关闭状态
mIntention = INTENTION_LEFT_OPEN;
setBackGroundVisible(true, false);
} else if (mXScrollDistance > 0) {//右边的btn显示出来的
mIntention = INTENTION_RIGHT_CLOSE;
} else if (mXScrollDistance < 0) {//左边的btn显示出来的
mIntention = INTENTION_LEFT_ALREADY_OPEN;
}
} else if (moveDistance < 0) {//往左
if (mXScrollDistance == 0) {//关闭状态
mIntention = INTENTION_RIGHT_OPEN;
setBackGroundVisible(false, true);
} else if (mXScrollDistance > 0) {//右边的btn显示出来的
mIntention = INTENTION_RIGHT_ALREADY_OPEN;
} else if (mXScrollDistance < 0) {//左边的btn显示出来的
mIntention = INTENTION_LEFT_CLOSE;
}
}
//计算出距离
switch (mIntention) {
case INTENTION_LEFT_CLOSE:
case INTENTION_LEFT_OPEN:
case INTENTION_LEFT_ALREADY_OPEN:
float distanceLeft = mXScrollDistance - moveDistance < 0 ? mXScrollDistance - moveDistance : 0;
if (!mWannaOver) {
distanceLeft = distanceLeft < -mBtnLeftTotalWidth ? -mBtnLeftTotalWidth : distanceLeft;
}
//滑动
mItemCustomLayout.scrollTo((int) distanceLeft, 0);
break;
case INTENTION_RIGHT_CLOSE:
case INTENTION_RIGHT_OPEN:
case INTENTION_RIGHT_ALREADY_OPEN:
float distanceRight = mXScrollDistance - moveDistance > 0 ? mXScrollDistance - moveDistance : 0;
if (!mWannaOver) {
distanceRight = distanceRight < mBtnRightTotalWidth ? distanceRight : mBtnRightTotalWidth;
}
mItemCustomLayout.scrollTo((int) distanceRight, 0);
break;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//todo 有待优化这里的代码
switch (mIntention) {
case INTENTION_LEFT_CLOSE:
case INTENTION_LEFT_OPEN:
case INTENTION_LEFT_ALREADY_OPEN:
//如果滑出的话,那么就滑到固定位置(只要滑出了 mBtnLeftTotalWidth / 2 ,就算滑出去了)
if (Math.abs(mItemCustomLayout.getScrollX()) > mBtnLeftTotalWidth / 2) {
//滑出
mIntention = INTENTION_LEFT_OPEN;
int delta = mBtnLeftTotalWidth - Math.abs(mItemCustomLayout.getScrollX());
if (Math.abs(mItemCustomLayout.getScrollX()) < mBtnLeftTotalWidth) {
mScroller.startScroll(mItemCustomLayout.getScrollX(), 0, -delta, 0, SCROLL_QUICK_TIME);
} else {
mScroller.startScroll(mItemCustomLayout.getScrollX(), 0, -delta, 0, SCROLL_TIME);
}
if (mOnItemSlideListenerProxy != null && mScrollState != SCROLL_STATE_OPEN) {
mOnItemSlideListenerProxy.onSlideOpen(this, MenuItem.DIRECTION_LEFT);
}
mScrollState = SCROLL_STATE_OPEN;
} else {
mIntention = INTENTION_LEFT_CLOSE;
mScroller.startScroll(mItemCustomLayout.getScrollX(), 0, -mItemCustomLayout.getScrollX(), 0, SCROLL_TIME);
//滑回去,归位
if (mOnItemSlideListenerProxy != null && mScrollState != SCROLL_STATE_CLOSE) {
mOnItemSlideListenerProxy.onSlideClose(this, MenuItem.DIRECTION_LEFT);
}
mScrollState = SCROLL_STATE_CLOSE;
}
break;
case INTENTION_RIGHT_CLOSE:
case INTENTION_RIGHT_OPEN:
case INTENTION_RIGHT_ALREADY_OPEN:
if (Math.abs(mItemCustomLayout.getScrollX()) > mBtnRightTotalWidth / 2) {
//滑出
mIntention = INTENTION_RIGHT_OPEN;
int delta = mBtnRightTotalWidth - Math.abs(mItemCustomLayout.getScrollX());
if (Math.abs(mItemCustomLayout.getScrollX()) < mBtnRightTotalWidth) {
mScroller.startScroll(mItemCustomLayout.getScrollX(), 0, delta, 0, SCROLL_QUICK_TIME);
} else {
mScroller.startScroll(mItemCustomLayout.getScrollX(), 0, delta, 0, SCROLL_TIME);
}
if (mOnItemSlideListenerProxy != null && mScrollState != SCROLL_STATE_OPEN) {
mOnItemSlideListenerProxy.onSlideOpen(this, MenuItem.DIRECTION_RIGHT);
}
mScrollState = SCROLL_STATE_OPEN;
} else {
mIntention = INTENTION_RIGHT_CLOSE;
mScroller.startScroll(mItemCustomLayout.getScrollX(), 0, -mItemCustomLayout.getScrollX(), 0, SCROLL_TIME);
//滑回去,归位
if (mOnItemSlideListenerProxy != null && mScrollState != SCROLL_STATE_CLOSE) {
mOnItemSlideListenerProxy.onSlideClose(this, MenuItem.DIRECTION_RIGHT);
}
mScrollState = SCROLL_STATE_CLOSE;
}
break;
}
// mIntention = INTENTION_ZERO;
postInvalidate();
mIsMoving = false;
break;
default:
break;
}
return true;
}

/**
* 设置哪边显示哪边不显示
*
* @param leftVisible
* @param rightVisible
*/
private void setBackGroundVisible(boolean leftVisible, boolean rightVisible) {
if (leftVisible) {
if (mItemLeftBackGroundLayout.getVisibility() != VISIBLE) {
mItemLeftBackGroundLayout.setVisibility(VISIBLE);
}
} else {
if (mItemLeftBackGroundLayout.getVisibility() == VISIBLE) {
mItemLeftBackGroundLayout.setVisibility(GONE);
}
}
if (rightVisible) {
if (mItemRightBackGroundLayout.getVisibility() != VISIBLE) {
mItemRightBackGroundLayout.setVisibility(VISIBLE);
}
} else {
if (mItemRightBackGroundLayout.getVisibility() == VISIBLE) {
mItemRightBackGroundLayout.setVisibility(GONE);
}
}
}

/**
* 上下左右不能超出50
*
* @param ev
* @return
*/
private boolean fingerNotMove(MotionEvent ev) {
return (mXDown - ev.getX() < 25 && mXDown - ev.getX() > -25 &&
mYDown - ev.getY() < 25 && mYDown - ev.getY() > -25);
}

/**
* 左右得超出50,上下不能超出50
*
* @param ev
* @return
*/
private boolean fingerLeftAndRightMove(MotionEvent ev) {
return ((ev.getX() - mXDown > 25 || ev.getX() - mXDown < -25) &&
ev.getY() - mYDown < 25 && ev.getY() - mYDown > -25);
}

/**
* 删除Item
*/
public void deleteItem(final OnItemDeleteListenerProxy onItemDeleteListenerProxy) {
scrollBack();
Animation.AnimationListener animationListener = new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {
if (onItemDeleteListenerProxy != null) {
onItemDeleteListenerProxy.onDelete(ItemMainLayout2.this);
}
}

@Override
public void onAnimationRepeat(Animation animation) {

}
};
final int originHeight = mHeight;
Animation animation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
//FIXME:5.0以下有个bug...就是当notifyDataChanged的时候,这个item bgImage与这个item上边的的item bgImage高度不能占完全item高度
if (!Compat.afterLollipop()) {
if (interpolatedTime > 0.9f) {
mHeight = originHeight;
} else {
mHeight = originHeight - (int) (originHeight * interpolatedTime * 10 / 9);
}
} else {
if (interpolatedTime == 1f) {
mHeight = originHeight;
} else {
mHeight = originHeight - (int) (originHeight * interpolatedTime);
}
}
ItemMainLayout2.this.requestLayout();
}

@Override
public boolean willChangeBounds() {
return true;
}
};
animation.setAnimationListener(animationListener);
animation.setDuration(SCROLL_DELETE_TIME);
startAnimation(animation);
}

@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
mItemCustomLayout.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
if (mScroller.isFinished()) {
switch (mIntention) {
case INTENTION_LEFT_CLOSE:
case INTENTION_RIGHT_CLOSE:
case INTENTION_SCROLL_BACK:
setBackGroundVisible(false, false);
break;
}
mIntention = INTENTION_ZERO;
}
}
super.computeScroll();
}

/**
* 归位
*/
protected void scrollBack() {
mIntention = INTENTION_SCROLL_BACK;
mScroller.startScroll(mItemCustomLayout.getScrollX(), 0, -mItemCustomLayout.getScrollX(), 0, SCROLL_BACK);
postInvalidate();
}

/**
* 设置item滑动的监听器
*
* @param onItemSlideListenerProxy
*/
protected void setOnItemSlideListenerProxy(OnItemSlideListenerProxy onItemSlideListenerProxy) {
mOnItemSlideListenerProxy = onItemSlideListenerProxy;
}

protected interface OnItemSlideListenerProxy {
void onSlideOpen(View view, int direction);

void onSlideClose(View view, int direction);
}

protected interface OnItemDeleteListenerProxy {
void onDelete(View view);
}
}