package framework.listview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Scroller;
/**
* @author yang 抽屉效果的ListView,配合SlideListAdapter使用
*/
public class SlideListView extends ListView {
static final int STATUS_NORMAL = 1;// 正常状态
static final int STATUS_SLIDING = 2;// 滑动中
static final int STATUS_STRETCH = 3;// item滑出状态
int status = STATUS_NORMAL;
int currentPosition;// 当前操作下标
int downY = -1;// /手指按下X的坐标
int downX = -1;// 手指按下Y的坐标
VelocityTracker velocityTracker;// 速度跟踪对象
Scroller scroller;
View currentItem;
public SlideListView(Context context, AttributeSet attrs) {
super(context, attrs);
scroller = new Scroller(context);
}
public SlideListView(Context context) {
this(context, null);
}
void reset() {
downX = -1;
downY = -1;
status = STATUS_NORMAL;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// 滚动未结束,直接返回
if (!scroller.isFinished()) {
return super.dispatchTouchEvent(event);
}
downX = (int) event.getX();
downY = (int) event.getY();
int slidePosition = pointToPosition(downX, downY);
if (status == STATUS_STRETCH) {
if (currentPosition != slidePosition) {
fold();
reset();
return true;
} else {
status = STATUS_NORMAL;
}
}
currentPosition = slidePosition;
// 无效的position,直接返回
if (currentPosition == AdapterView.INVALID_POSITION) {
return super.dispatchTouchEvent(event);
}
currentItem = getChildAt(currentPosition - getFirstVisiblePosition());
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
@SuppressLint({ "ClickableViewAccessibility", "Recycle" })
@Override
public boolean onTouchEvent(MotionEvent event) {
if (downX != -1 && currentPosition != AdapterView.INVALID_POSITION && canSlide()) {
requestDisallowInterceptTouchEvent(true);
addVelocityTracker(event);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
// 解除item click事件
MotionEvent cancelEvent = MotionEvent.obtain(event);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL | (event.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
onTouchEvent(cancelEvent);
int ex = (int) event.getX();
int x = downX - ex;
if (x > 0) {
if (x + currentItem.getScrollX() > getSlideWidth()) {
x = getSlideWidth() - currentItem.getScrollX();
}
}
if (x < 0) {
if (x + currentItem.getScrollX() < 0) {
x = 0 - currentItem.getScrollX();
}
}
currentItem.scrollBy(x, 0);
downX = ex;
return true;
case MotionEvent.ACTION_UP:
evalPointUp();
removeVelocityTracker();
break;
default:
break;
}
}
return super.onTouchEvent(event);
}
/**
* 处理手指松开后的事件
*/
final void evalPointUp() {
int velocityX = getScrollVelocity();
int validWidth = getSlideWidth() / 3;
if (Math.abs(velocityX) > validWidth) {
if (velocityX < 0)
stretch();
else
fold();
} else {
if (velocityX < 0)
fold();
else
stretch();
}
if (velocityX == 0) {
if (currentItem.getScrollX() > getSlideWidth() / 3)
stretch();
else
fold();
}
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
currentItem.scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
/**
* 滑出状态
*/
if (currentItem.getScrollX() == getSlideWidth()) {
status = STATUS_STRETCH;
}
}
}
/**
* 获取可滑出的总宽度
*/
int getSlideWidth() {
if (getAdapter() instanceof SlideListAdapter) {
return ((SlideListAdapter) getAdapter()).getButtonsWidth(currentPosition);
}
return 0;
}
/**
* 滑出
*/
void stretch() {
scroller.startScroll(currentItem.getScrollX(), 0, getSlideWidth() - currentItem.getScrollX(), 0);
postInvalidate();
}
/**
* 收回
*/
void fold() {
scroller.startScroll(currentItem.getScrollX(), 0, 0 - currentItem.getScrollX(), 0);
postInvalidate();
}
/**
* 是否可滑动
*/
public boolean canSlide() {
return getSlideWidth() > 0 && status == STATUS_NORMAL || status == STATUS_SLIDING;
}
private void addVelocityTracker(MotionEvent event) {
if (velocityTracker == null) {
velocityTracker = VelocityTracker.obtain();
}
velocityTracker.addMovement(event);
}
private void removeVelocityTracker() {
if (velocityTracker != null) {
velocityTracker.recycle();
velocityTracker = null;
}
}
/**
* 获取X方向的滑动速度
*/
private int getScrollVelocity() {
velocityTracker.computeCurrentVelocity(1000);
int velocity = (int) velocityTracker.getXVelocity();
return velocity;
}
}