首先声明,此博文得益于一叶漂舟大神的点击打开链接的博客,谢谢分享。
这里只实现当有滑动速度时才会出现删除按钮,而不是像qq那样随着滑动一点一点出来的,qq那个后面再研究。
先看自定义的View的代码:
package com.hardy.person.housingestate.activities; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; import com.hardy.person.housingestate.R; /** * @author 马鹏昊 * @date {2016-10-12} * @des 自定义左滑删除ListView * @updateAuthor * @updateDate * @updateDes */ public class MyListView extends ListView implements View.OnTouchListener,GestureDetector.OnGestureListener{ private String TAG = "MyListView"; //GestureDetector对象,注意要使用android.view.GestureDetector这个包下的 private GestureDetector gestureDetector ; //自定义删除回调接口 private OnDeleteListener listener; //删除按钮 private View deleteButton; //触发左滑事件的Item private ViewGroup itemLayout; //记录触发触摸事件的点是属于adapter哪个项(由pointToPosition方法获得) private int selectedItem; //标志着删除按钮是否已经出现 private boolean isDeleteShown; public MyListView(Context context) { super(context); } public MyListView(Context context,AttributeSet set) { super(context, set); //第二个参数是OnGestureListener对象 gestureDetector = new GestureDetector(getContext(),this); //一开始触摸事件会先被OnTouchListener捕获,在onTouch()方法里去分配事件给GestureDetector,他才会有资格处理 setOnTouchListener(this); } @Override public boolean onDown(MotionEvent e) { //测试三个方法的作用 //pointToPosition(x ,y )方法是得到指定的x、y点的Item在adapter中的位置 int po = pointToPosition((int) e.getX(), (int) e.getY()); Log.d(TAG, "pointToPosition()返回的值: " + po); //getFirstVisiblePosition()方法是得到屏幕中可见的第一个Item在adapter中的位置 int firstVisiblePosition = getFirstVisiblePosition(); Log.d(TAG, "getFirstVisiblePosition()返回的值: " + firstVisiblePosition); int index = po - firstVisiblePosition ; Log.d(TAG, "pointToPosition()返回的值 - getFirstVisiblePosition()返回的值: "+index); //getChildAt(index)方法是得到在屏幕中可见的这些Item中的index位置的Item,index不是在adapter中的位置,而是屏幕中可见的Item的位置 TextView textView = (TextView) getChildAt(index); Log.d(TAG, "得到的ItemView的值: " + textView.getText().toString()); //如果删除按钮还不可见,得到点击的是在adapter中的位置 if (!isDeleteShown) { selectedItem = pointToPosition((int) e.getX(), (int) e.getY()); } return false; } //设置删除listener public void setOnDeleteListener(OnDeleteListener l) { listener = l; } //只要是按下没有抬起时触发,而onLongPress是当按住到达一定时间才能触发 @Override public void onShowPress(MotionEvent e) { } //没有滑动,单击up时触发 @Override public boolean onSingleTapUp(MotionEvent e) { return false; } //当滑动时触发,并且distanceX和distanceY是上一次触发onScroll时的x、y到此次onScroll时的相应的距离,并不是到onDown时的相应距离 @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } //毋庸置疑,当长按时触发 @Override public void onLongPress(MotionEvent e) { } //当滑动的事件up时有加速度时触发 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { //如果删除按钮还不可见,并且x方向的加速度大于y方向的加速度则证明是横行滑动的,则显示删除按钮 if (!isDeleteShown && Math.abs(velocityX) > Math.abs(velocityY)) { //通过inflater得到删除按钮 deleteButton = LayoutInflater.from(getContext()).inflate( R.layout.delete_button, null); //添加点击事件 deleteButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //从触发左滑事件的Item中移除掉删除按钮 itemLayout.removeView(deleteButton); deleteButton = null; //标志删除按钮不可见 isDeleteShown = false; //执行删除时你要做的回调方法(移除该Item) listener.onDelete(selectedItem); } }); //找到触发左滑事件的Item itemLayout = (ViewGroup) getChildAt(selectedItem - getFirstVisiblePosition()); //设置要添加的删除按钮的参数和对齐方式 RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); //addRule()方法设置layout动词,可以理解为设置对齐方式 params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); params.addRule(RelativeLayout.CENTER_VERTICAL); // //设置要添加的删除按钮的参数和对齐方式 // LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( // LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); //给该Item添加删除按钮 itemLayout.addView(deleteButton, params); //标志删除按钮可见 isDeleteShown = true; } return false; } @Override public boolean onTouch(View v, MotionEvent event) { //如果删除按钮现在正可见,那么本次点击后,删除按钮隐藏 if (isDeleteShown) { itemLayout.removeView(deleteButton); deleteButton = null; //标志删除按钮不可见 isDeleteShown = false; return false; } else { //否则把触摸事件交给GestureDetector去处理左滑事件 return gestureDetector.onTouchEvent(event); } } //删除回调接口 public interface OnDeleteListener { void onDelete(int index); } }仔细看注释就能明白。
特意说一下:
触摸事件首先会被onTouchListener捕获,所以GestureDetector要想处理触摸事件必须在onTouch()方法里被分配了事件才行,所以整个事件的入口在onTouch()。
//否则把触摸事件交给GestureDetector去处理左滑事件 return gestureDetector.onTouchEvent(event);Activity里设置删除监听方法和adapter即可:
final List<String> contentList = new ArrayList<>(); contentList.add("Content Item 1"); contentList.add("Content Item 2"); contentList.add("Content Item 3"); contentList.add("Content Item 4"); contentList.add("Content Item 5"); contentList.add("Content Item 6"); contentList.add("Content Item 7"); contentList.add("Content Item 8"); contentList.add("Content Item 9"); contentList.add("Content Item 10"); contentList.add("Content Item 11"); contentList.add("Content Item 12"); contentList.add("Content Item 13"); contentList.add("Content Item 14"); contentList.add("Content Item 15"); contentList.add("Content Item 16"); contentList.add("Content Item 17"); contentList.add("Content Item 18"); contentList.add("Content Item 19"); contentList.add("Content Item 20"); final ArrayAdapter arrayAdapter = new ArrayAdapter(this,R.layout.asdasdasd,R.id.text,contentList); MyListView myListView = (MyListView) findViewById(R.id.asd); myListView.setOnDeleteListener(new MyListView.OnDeleteListener() { @Override public void onDelete(int index) { contentList.remove(index); arrayAdapter.notifyDataSetChanged(); } }); myListView.setAdapter(arrayAdapter);ok!完工!!