//需要修改ListView类 重写onInterceptTouchEvent()和onTouchEvent() //试验了另一种方法,改写ListView的每一行中拖曳图标的 onTouchEvent(),但效果不理想。 public class MainActivity extends Activity { DeleteAdapter deleteAdapter; DragListView listView; boolean bFlag; ImageButton button; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); deleteAdapter = new DeleteAdapter(this, getData()); listView = (DragListView) findViewById(R.id.listView1); listView.setAdapter(deleteAdapter); button = (ImageButton) findViewById(R.id.imageButton1); bFlag = false; button.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub if (!bFlag) { deleteAdapter.imgVisibility = true; button.setPressed(true); bFlag = true; deleteAdapter.notifyDataSetChanged(); listView.setSelector(android.R.color.transparent); } else { deleteAdapter.imgVisibility = false; deleteAdapter.imgVisible = new boolean[deleteAdapter .getCount()]; button.setPressed(false); bFlag = false; deleteAdapter.notifyDataSetChanged(); listView.setSelector(android.R.drawable.list_selector_background); } } }); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub if (bFlag) { if (deleteAdapter.imgDVisible) { deleteAdapter.imgDVisible = false; deleteAdapter.imgVisible = new boolean[deleteAdapter.getCount()]; deleteAdapter.notifyDataSetChanged(); } } } }); } private List<HashMap<String, Object>> getData() { // 新建一个集合类,用于存放多条数据 ArrayList<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>(); HashMap<String, Object> map = null; for (int i = 1; i <= 100; i++) { map = new HashMap<String, Object>(); map.put("title", i); map.put("img", R.drawable.img); map.put("imgD", R.drawable.imgd); map.put("imgDrag", R.drawable.imgdrag); list.add(map); } return list; } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } } <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageButton android:id="@+id/imageButton1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:src="@drawable/ic_launcher" /> <com.example.test.DragListView android:id="@+id/listView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_below="@+id/imageButton1" > </com.example.test.DragListView> </RelativeLayout> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/img" android:visibility="invisible" /> <TextView android:id="@+id/textView1" android:layout_width="150dp" android:layout_height="match_parent" /> <ImageView android:id="@+id/imageDrag" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/imgdrag" android:visibility="invisible" android:focusable="false"/> <ImageView android:id="@+id/imageD" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/imgd" android:visibility="invisible" /> </LinearLayout> public class DeleteAdapter extends BaseAdapter { List<HashMap<String, Object>> text; Context context; private LayoutInflater mInflater; boolean imgVisibility = false; boolean imgVisible[] ;//记录删除按钮可见位置的标记数组 boolean imgDVisible = false; public DeleteAdapter(Context context, List<HashMap<String, Object>> text) { this.text = text; this.mInflater = LayoutInflater.from(context); imgVisible = new boolean[text.size()]; } @Override public int getCount() { // TODO Auto-generated method stub return text.size(); } @Override public Object getItem(int arg0) { // TODO Auto-generated method stub return text.get(arg0); } @Override public long getItemId(int arg0) { // TODO Auto-generated method stub return 0; } public void remove(Object object) { text.remove(object); notifyDataSetChanged(); } @SuppressWarnings("unchecked") public void insert(Object object, int i) { text.add(i, (HashMap<String, Object>) object); notifyDataSetChanged(); } @Override public View getView(final int arg0, View arg1, ViewGroup arg2) { // TODO Auto-generated method stub arg1 = mInflater.inflate(R.layout.listview_item, null); TextView textView = (TextView) arg1.findViewById(R.id.textView1); textView.setText(text.get(arg0).get("title").toString()); final ImageView img = (ImageView) arg1.findViewById(R.id.image); img.setBackgroundResource((Integer) text.get(arg0).get("img")); final ImageView imgD = (ImageView) arg1.findViewById(R.id.imageD); imgD.setBackgroundResource((Integer) text.get(arg0).get("imgD")); final ImageView imgDrag = (ImageView) arg1.findViewById(R.id.imageDrag); imgDrag.setBackgroundResource((Integer) text.get(arg0).get("imgDrag")); if (imgVisibility) { img.setVisibility(View.VISIBLE); imgDrag.setVisibility(View.VISIBLE); } if (imgVisibility && !imgDVisible ) { img.setVisibility(View.VISIBLE); imgD.setVisibility(View.INVISIBLE); imgDrag.setVisibility(View.VISIBLE); img.setClickable(true); img.setFocusable(true); } if (imgVisibility && imgDVisible && imgVisible[arg0]){ img.setVisibility(View.INVISIBLE); imgD.setVisibility(View.VISIBLE); } img.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub // imgD.setVisibility(View.VISIBLE); // img.setVisibility(View.INVISIBLE); imgVisible[arg0] = true; imgDVisible = true; notifyDataSetChanged(); } }); imgD.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub text.remove(arg0); imgDVisible = false; imgVisible[arg0] = false; notifyDataSetChanged(); } }); if (imgVisibility && imgDVisible ) { img.setClickable(false); img.setFocusable(false); } return arg1; } } //设置了 setClickable(false); //但是,按钮仍然会相应点击事件。后来发现 setOnClickListener//里的一段代码 if (!isClickable()) { setClickable(true); } //这导致了 setOnClickListener之前的setClickable(false)//方法没有起作用。 //Button.setClickable() 要在Button.setOnClickListener()后设置,否则不管setClickable的值为//否,都为true public class DragListView extends ListView { private ImageView dragImageView;// 被拖拽项的影像,其实就是一个ImageView private int dragSrcPosition;// 手指拖动项原始在列表中的位置 private int dragPosition;// 手指拖动的时候,当前拖动项在列表中的位置 private int dragPoint;// 在当前数据项中的位置 private int dragOffset;// 当前视图和屏幕的距离(这里只使用了y方向上) private WindowManager windowManager;// windows窗口控制类 private WindowManager.LayoutParams windowParams;// 用于控制拖拽项的显示的参数 private int scaledTouchSlop;// 判断滑动的一个距离 private int upScrollBounce;// 拖动的时候,开始向上滚动的边界 private int downScrollBounce;// 拖动的时候,开始向下滚动的边界 public DragListView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // 捕获down事件 if (ev.getAction() == MotionEvent.ACTION_DOWN) { int x = (int) ev.getX(); int y = (int) ev.getY(); // 选中的数据项位置,使用ListView自带的pointToPosition(x, y)方法 dragSrcPosition = dragPosition = pointToPosition(x, y); // 如果是无效位置(超出边界,分割线等位置),返回 if (dragPosition == AdapterView.INVALID_POSITION) { return super.onInterceptTouchEvent(ev); } // 获取选中项View // getChildAt(int position)显示display在界面的position位置的View // getFirstVisiblePosition()返回第一个display在界面的view在adapter的位置position,可能是0,也可能是4 ViewGroup itemView = (ViewGroup) getChildAt(dragPosition - getFirstVisiblePosition()); // dragPoint点击位置在点击View内的相对位置 // dragOffset屏幕位置和当前ListView位置的偏移量,这里只用到y坐标上的值 // 这两个参数用于后面拖动的开始位置和移动位置的计算 dragPoint = y - itemView.getTop(); dragOffset = (int) (ev.getRawY() - y); // 获取右边的拖动图标,这个对后面分组拖拽有妙用 View dragger = itemView.findViewById(R.id.imageDrag); DeleteAdapter deleteAdapter = (DeleteAdapter) getAdapter(); // 如果在右边位置(拖拽图片左边的20px的右边区域) if (dragger != null && x > dragger.getLeft() && x < dragger.getRight() && !deleteAdapter.imgDVisible) { // 准备拖动 // 初始化拖动时滚动变量 // scaledTouchSlop定义了拖动的偏差位(一般+-10) // upScrollBounce当在屏幕的上部(上面1/3区域)或者更上的区域,执行拖动的边界,downScrollBounce同理定义 upScrollBounce = Math.min(y - scaledTouchSlop, getHeight() / 3); downScrollBounce = Math.max(y + scaledTouchSlop, getHeight() * 2 / 3); // 设置Drawingcache为true,获得选中项的影像bm,就是后面我们拖动的哪个头像 itemView.setDrawingCacheEnabled(true); Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache()); // 准备拖动影像(把影像加入到当前窗口,并没有拖动,拖动操作我们放在onTouchEvent()的move中执行) startDrag(bm, y); } return false; } return super.onInterceptTouchEvent(ev); } public void startDrag(Bitmap bm, int y) { // 释放影像,在准备影像的时候,防止影像没释放,每次都执行一下 stopDrag(); windowParams = new WindowManager.LayoutParams(); // 从上到下计算y方向上的相对位置, windowParams.gravity = Gravity.TOP; windowParams.x = 0; windowParams.y = y - dragPoint + dragOffset; windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT; windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; // 下面这些参数能够帮助准确定位到选中项点击位置,照抄即可 windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; windowParams.format = PixelFormat.TRANSLUCENT; windowParams.windowAnimations = 0; // 把影像ImagView添加到当前视图中 ImageView imageView = new ImageView(getContext()); imageView.setImageBitmap(bm); windowManager = (WindowManager) getContext().getSystemService("window"); windowManager.addView(imageView, windowParams); // 把影像ImageView引用到变量drawImageView,用于后续操作(拖动,释放等等) dragImageView = imageView; } public void stopDrag() { if (dragImageView != null) { windowManager.removeView(dragImageView); dragImageView = null; } } @Override public boolean onTouchEvent(MotionEvent ev) { // 如果dragmageView为空,说明拦截事件中已经判定仅仅是点击,不是拖动,返回 // 如果点击的是无效位置,返回,需要重新判断 if (dragImageView != null && dragPosition != INVALID_POSITION) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_UP: int upY = (int) ev.getY(); // 释放拖动影像 stopDrag(); // 放下后,判断位置,实现相应的位置删除和插入 onDrop(upY); break; case MotionEvent.ACTION_MOVE: int moveY = (int) ev.getY(); // 拖动影像 onDrag(moveY); break; default: break; } return true; } // 这个返回值能够实现selected的选中效果,如果返回true则无选中效果 return super.onTouchEvent(ev); } public void onDrag(int y) { if (dragImageView != null) { windowParams.alpha = 0.8f; windowParams.y = y - dragPoint + dragOffset; windowManager.updateViewLayout(dragImageView, windowParams); } // 为了避免滑动到分割线的时候,返回-1的问题 int tempPosition = pointToPosition(0, y); if (tempPosition != INVALID_POSITION) { dragPosition = tempPosition; } // 滚动 int scrollHeight = 0; if (y < upScrollBounce) { scrollHeight = 8;// 定义向上滚动8个像素,如果可以向上滚动的话 } else if (y > downScrollBounce) { scrollHeight = -8;// 定义向下滚动8个像素,,如果可以向上滚动的话 } if (scrollHeight != 0) { // 真正滚动的方法setSelectionFromTop() setSelectionFromTop(dragPosition, getChildAt(dragPosition - getFirstVisiblePosition()) .getTop() + scrollHeight); } } public void onDrop(int y){ //获取放下位置在数据集合中position //定义临时位置变量为了避免滑动到分割线的时候,返回-1的问题,如果为-1,则不修改dragPosition的值,急需执行,达到跳过无效位置的效果 int tempPosition = pointToPosition(0, y); if(tempPosition!=INVALID_POSITION){ dragPosition = tempPosition; } //超出边界处理 if(y<getChildAt(0).getTop()){ //超出上边界,设为最小值位置0 dragPosition = 0; }else if(y>getChildAt(getChildCount()-1).getBottom()){ //超出下边界,设为最大值位置,注意哦,如果大于可视界面中最大的View的底部则是越下界,所以判断中用getChildCount()方法 //但是最后一项在数据集合中的position是getAdapter().getCount()-1,这点要区分清除 dragPosition = getAdapter().getCount()-1; } //数据更新 if(dragPosition>0&&dragPosition<getAdapter().getCount()){ DeleteAdapter adapter = (DeleteAdapter)getAdapter(); Object dragItem = adapter.getItem(dragSrcPosition); //删除原位置数据项 adapter.remove(dragItem); //在新位置插入拖动项 adapter.insert(dragItem, dragPosition); } } }