//需要修改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);
	    }
	}
}

 

posted on 2014-12-22 12:16  Luscinia  阅读(1443)  评论(0编辑  收藏  举报