android listview滑动删除,实现item的点击缩回

时间:2021-10-22 21:15:43

 最近有一个滑动删除列表的需求,本来以为很简单的,做的和QQ的一样就好,结果自己写发现不是这么回事,QQ的滑动删除是滑动就打开,再触碰除了打开的区域以外的区域,打开的item就回缩,其实就是状态的判断,但是我的判断似乎总是出问题,于是用了点小技巧,现在的功能是实现了,滑动打开,点击其他地方就回缩,特此记录。android listview滑动删除,实现item的点击缩回

android listview滑动删除,实现item的点击缩回
其实主要还是滑动事件的分发和item状态的判断,我这里参考了http://blog.csdn.net/harvic880925/article/details/45317951http://blog.csdn.net/harvic880925/article/details/45317951这篇博客,把自定义listview改成自定义linearlayout,由layout自己实现回滚,这样就只需要处理好打开关闭状态就行了,下面看代码
/**
* 滑动的监听,传递当前滑动的layout和状态(打开或者关闭),用于action_up
*/
public static interface OnScrollListener {
public void onScroll(DeleteLinearLayout view,int state);
}

public void setOnScrollListenre(OnScrollListener onScrollListener) {
this.onScrollListener = onScrollListener;
}

/**
* 触碰的监听,传递当前触碰的layout,用于action_down
*/
public static interface OnTouchListener {
public void onTouch(DeleteLinearLayout view);
}

public void setOnTouchListener(OnTouchListener onTouchListener) {
this.onTouchListener = onTouchListener;
}

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

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

public DeleteLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}

private void init(Context context) {
this.context = context;
mScroller = new Scroller(context, new LinearInterpolator(context, null));
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
int maxLength = 300;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
xDistance = yDistance = 0f;
xLast = ev.getX();
yLast = ev.getY();
currentX = (int) ev.getX();
mlastX = (int) ev.getX();
xDistance = yDistance = 0f;
xLast = ev.getX();
yLast = ev.getY();
onTouchListener.onTouch(this);
}
break;
case MotionEvent.ACTION_MOVE: {
//如果当前状态是关闭状态才执行,相当于拦截了打开状态的action_move
if(!Utils.getSP(context)) {
final float curX = ev.getX();
final float curY = ev.getY();

// 计算在X和Y方向的偏移量
xDistance += Math.abs(curX - xLast);
yDistance += Math.abs(curY - yLast);
xLast = curX;
yLast = curY;
// 横向距离大于纵向距离,layout才可以滑动
if (xDistance > yDistance && xDistance >touchSlop) {
currentX = (int) ev.getX();
int scrollX = getScrollX();
int reallyX = scrollX + mlastX - currentX;
if (reallyX < 0) {
reallyX = 0;
} else if (reallyX > maxLength) {
reallyX = maxLength;
}
this.scrollTo(reallyX, 0);
mlastX = currentX;
}
}
}
break;
case MotionEvent.ACTION_UP: {
//无论是否拦截action_move,都会进来这一步,所以如果拦截了action_move,reallyX 为0,把当前状态设为了关闭
int scrollX = this.getScrollX();
int reallyX = scrollX + mlastX - currentX;
if (scrollX > maxLength / 2) {
reallyX = maxLength;
CURRENT_STATE = STATE_OPEN;
//保存listview当前的状态为打开
Utils.setSP(context,true);
} else {
CURRENT_STATE = STATE_CLOSE;
//保存listview当前的状态为关闭
Utils.setSP(context,false);
reallyX = 0;
}
onScrollListener.onScroll(this,CURRENT_STATE);
mScroller.startScroll(scrollX, 0, reallyX - scrollX, 0);
invalidate();
}
break;
}
return super.onTouchEvent(ev);
}

@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
this.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
}
invalidate();
}

//提供给外面调用的方法,用于使layout滚回原点
public void smoothScrollTo(int x, int y) {
int scrollX = getScrollX();
int deltaX = x - scrollX;
mScroller.startScroll(scrollX, 0, deltaX, 0);
invalidate();
}

然后是MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (MyListView) findViewById(R.id.listview);
for (int i = 0; i < 200; i++) {
MyAdapter.Data data = new MyAdapter.Data();
data.title = (i + "个人");
list.add(data);
}
adapter = new MyAdapter(this, list, new View.OnClickListener() {
@Override
public void onClick(View v) {
if(v.getId() == R.id.del) {
int positon = listView.getPositionForView(v);
Utils.setSP(MainActivity.this,false);
adapter.removeItem(positon);
curState = 2;
adapter.notifyDataSetChanged();
}
}
}, new DeleteLinearLayout.OnScrollListener() {
@Override
public void onScroll(DeleteLinearLayout view, int state) {
if (state == 1) {
lastLayout = view;
}
curState = state;
}
}, new DeleteLinearLayout.OnTouchListener() {
@Override
public void onTouch(DeleteLinearLayout view) {
if (curState == 1) {
lastLayout.smoothScrollTo(0, 0);
}
}
});
listView.setAdapter(adapter);
}

@Override
protected void onDestroy() {
super.onDestroy();
Utils.setSP(this,false);

自定义的listview,不处理具体事件
public boolean onTouchEvent(MotionEvent event) {
    int maxLength = 300;

int currentY = (int) event.getY();

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
currentX = (int) event.getX();
//我们想知道当前点击了哪一行
int position = pointToPosition(currentX, currentY);
if (position != INVALID_POSITION) {
MyAdapter.Data data = (MyAdapter.Data) getItemAtPosition(position);
itemLayout = data.listLayout;
Log.e("Listview action down: ","valid positon");
} else {
Log.e("Listview action down: ","invalid positon");

}
}

case MotionEvent.ACTION_MOVE:
final float curX = event.getX();
final float curY = event.getY();

// 计算在X和Y方向的偏移量
xDistance += Math.abs(curX - xLast);
yDistance += Math.abs(curY - yLast);
xLast = curX;
yLast = curY;
break;
}
if (itemLayout != null) {
itemLayout.onTouchEvent(event);
} else {
}
if (xDistance > yDistance) {
return true;
}
return super.onTouchEvent(event);

}


@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
xDistance = yDistance = 0f;
xLast = ev.getX();
yLast = ev.getY();

break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
这里用了个小技巧,就是用sharepreferences保存了linearlayout的当前状态,第一次点击,
Utils.getSP()返回false,因此可以滑动,走到action_up,如果最后状态为打开,则将
sharepreferences设置为true,那么第二次点击的时候,就不会进去action_move,故不会滑动,但是还会进入action_up,最后状态由于action_move的时候没有滑动,为关闭状态,因此把shareprefer置为false,一直循环。
主要是正规的方法想不出来。