根据网友的分享修改的例子,实现了listview侧滑删除效果。
当侧滑的距离小于屏幕尺寸三分之一的时候,就回复。否则如果向右侧滑动超过三分之一,就移动到右侧边界外,然后删除该子项,如果是向左侧滑动超过三分之一,就移动到左侧边界外,然后删除该子项。
自定义Listview:
public class SlideListView extends ListView {
private Context mContext;
private int screenWidth;
private View itemView;
private Scroller scroller;
private TouchPoint downPoint = new TouchPoint(0, 0);
private RemoveListListener removeListListener;
public void setRemoveListListener(RemoveListListener listListener) {
this.removeListListener = listListener;
}
public SlideListView(Context context) {
super(context);
this.mContext = context;
init();
}
public SlideListView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
init();
}
public SlideListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.mContext = context;
init();
}
private void init() {
scroller = new Scroller(mContext);
screenWidth = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
}
/**
* 事件分发
*
* @param ev
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//scroller滚动未结束
if (!scroller.isFinished()) {
return super.dispatchTouchEvent(ev);
}
downPoint.setPointX((int) ev.getX());
downPoint.setPointY((int) ev.getY());
int itempos = pointToPosition(downPoint.getPointX(), downPoint.getPointY());
//无效的item
if (AdapterView.INVALID_POSITION == itempos) {
return super.dispatchTouchEvent(ev);
}
downPoint.setCurPos(itempos);
downPoint.setDownX(downPoint.getPointX());
//获取当前的item
itemView = getChildAt(itempos - getFirstVisiblePosition());
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
MotionEvent cancelEvent = MotionEvent.obtain(ev);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
(ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
onTouchEvent(cancelEvent);
float curX = ev.getX();
int space = downPoint.getPointX() - (int) curX;
downPoint.setPointX((int) curX);
itemView.scrollBy(space, 0);
break;
case MotionEvent.ACTION_UP:
scrollDistanceX();
break;
default:
break;
}
return super.onTouchEvent(ev);
}
/**
* 滑动
*/
private void scrollItemAnim(int delta) {
scroller.startScroll(itemView.getScrollX(), 0, delta, 0,
Math.abs(delta));
postInvalidate();
}
private void scrollDistanceX() {
//手指滑动的矢量距离
int scrollAbs = downPoint.getPointX() - downPoint.getDownX();
//以左侧边界为原点
if (Math.abs(scrollAbs) < screenWidth / 3) {
scrollItemAnim(scrollAbs);
} else {
if (scrollAbs > 0) {
scrollItemAnim(-screenWidth + scrollAbs);
} else {
scrollItemAnim(screenWidth + scrollAbs);
}
}
//强制停止滑动
// scroller.forceFinished(true);
}
@Override
public void computeScroll() {
super.computeScroll();
if (scroller.computeScrollOffset()) {
itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
if (scroller.isFinished()) {
if (null == removeListListener) {
throw new NullPointerException("null removelistener");
} else {
if (screenWidth / 4 < Math.abs(downPoint.getPointX() - downPoint.getDownX())) {
removeListListener.removeItem(downPoint.getCurPos());
}
}
}
}
}
public interface RemoveListListener {
public void removeItem(int pos);
}
private class TouchPoint {
private int pointX;
private int pointY;
private int curPos;
private int downX;
private TouchPoint(int pointX, int pointY) {
this.pointX = pointX;
this.pointY = pointY;
}
public int getPointX() {
return pointX;
}
public void setPointX(int pointX) {
this.pointX = pointX;
}
public int getPointY() {
return pointY;
}
public void setPointY(int pointY) {
this.pointY = pointY;
}
public int getCurPos() {
return curPos;
}
public void setCurPos(int curPos) {
this.curPos = curPos;
}
public int getDownX() {
return downX;
}
public void setDownX(int downX) {
this.downX = downX;
}
}
}
在dispatch中,处理事件的分发,让合适的事件才分发下去,在里面都有注释说明的。
获取屏幕的宽度,作为移动的距离大小的判断标准。
screenWidth = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
获取移动的子项。
pointToPosition(downPoint.getPointX(), downPoint.getPointY());
itemView = getChildAt(itempos - getFirstVisiblePosition());
取消在滑动中对listive的其他点击等事件。
MotionEvent cancelEvent = MotionEvent.obtain(ev);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
(ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
onTouchEvent(cancelEvent);
对滑动的判断,是分为四种情况的,向左滑动长度是否超过屏幕宽度的三分之一,向右滑动长度是否超过屏幕宽度的三分之一,下面是优化后的情况。
if (Math.abs(scrollAbs) < screenWidth / 3) {
scrollItemAnim(scrollAbs);
} else {
if (scrollAbs > 0) {
scrollItemAnim(-screenWidth + scrollAbs);
} else {
scrollItemAnim(screenWidth + scrollAbs);
}
}
scroll没有停止的时候,可以强制停止。
//强制停止滑动
// scroller.forceFinished(true);
声明的删除接口,给Listview提供移动删除的item。
public interface RemoveListListener {
public void removeItem(int pos);
}
computeScroll()源码注释,在这 我们使用了scroller.startScroll。
/**Called by a parent to request that a child update its values for mScrollX and mScrollY if necessary. This will typically be done if the child is animating a scroll using a Scroller object.*/
public void [More ...] computeScroll() {
}
/**
* Start scrolling by providing a starting point and the distance to travel.
*
* @param startX Starting horizontal scroll offset in pixels. Positive
* numbers will scroll the content to the left.
* @param startY Starting vertical scroll offset in pixels. Positive numbers
* will scroll the content up.
* @param dx Horizontal distance to travel. Positive numbers will scroll the
* content to the left.
* @param dy Vertical distance to travel. Positive numbers will scroll the
* content up.
* @param duration Duration of the scroll in milliseconds.
*/
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}
看到了吧,里面使用了动画来移动子项。
scrollTo()与scrollBy(),scrollBy()其实调用了scrollTo(),只是在传入的是x,y的偏移量。而scrollTo()y移动的是实际距离。
/**
* Set the scrolled position of your view. This will cause a call to
* {@link #onScrollChanged(int, int, int, int)} and the view will be
* invalidated.
* @param x the x position to scroll to
* @param y the y position to scroll to
*/
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
/**
* Move the scrolled position of your view. This will cause a call to
* {@link #onScrollChanged(int, int, int, int)} and the view will be
* invalidated.
* @param x the amount of pixels to scroll by horizontally
* @param y the amount of pixels to scroll by vertically
*/
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
活动:
public class MainActivity extends Activity {
private MainActivity mContext;
private List<String> list = new ArrayList<String>();
private SlideAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
setData();
SlideListView listView = (SlideListView) findViewById(R.id.slideview_list);
adapter = new SlideAdapter();
listView.setAdapter(adapter);
listView.setRemoveListListener(new SlideListView.RemoveListListener() {
@Override
public void removeItem(int pos) {
adapter.removeItem(pos);
}
});
}
private void setData() {
String[] str = new String[]{"one", "two", "three", "four"};
for (String s : str) {
list.add(s);
}
}
private class SlideAdapter extends BaseAdapter {
private SlideAdapter() {
}
public void removeItem(int pos) {
list.remove(pos);
this.notifyDataSetChanged();
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.item, null);
}
TextView textView = (TextView) convertView.findViewById(R.id.textView);
textView.setText(list.get(position));
return convertView;
}
}
}