Android 仿iPhone ListView拖动排序 按钮联动删除显示隐藏

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

	    }

	}

}

 

你可能感兴趣的:(ListView)