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