下面是个android ListView和GridView拖拽移位实现代码教程,撑握了其技术要点,学起来就简单多了。赶紧跟着图老师小编一起来看看吧!
【 tulaoshi.com - 编程语言 】
关于ListView拖拽移动位置,想必大家并不陌生,比较不错的软件都用到如此功能了.如:搜狐,网易,百度等,但是相比来说还是百度的用户体验较好,不偏心了,下面看几个示例:      
      
首先说一下:拖拽ListView的item就不应该可以任意移动,只应该在ListView所在的范围内,而网易的你看看我都可以移动到状态栏了,虽然你做了处理,但是用户体验我个人感觉不好,在看看百度的,不仅控制了移动范围,更不错的百度的移动起来会时时的换位,看起来相当的形象,所以我认为这样相当的棒.
说明一点,我没有那么有才,我也是看别人代码,然后自己整理下.在这里就简单记载一下.
首先对touch事件的处理,从应用中,我们可以得出,在我们点击后面拖拉图标后,就会创建一个item的影像视图.并且可以移动该影像,而此时的ListView不应该有touch事件.
onInterceptTouchEvent方法.
[java]
代码如下:
/*** 
* touch事件拦截 
*/ 
@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) { 
// 按下 
if (ev.getAction() == MotionEvent.ACTION_DOWN) { 
int x = (int) ev.getX();// 获取相对与ListView的x坐标 
int y = (int) ev.getY();// 获取相应与ListView的y坐标 
dragSrcPosition = dragPosition = pointToPosition(x, y); 
// 无效不进行处理 
if (dragPosition == AdapterView.INVALID_POSITION) { 
return super.onInterceptTouchEvent(ev); 
} 
// 获取当前位置的视图(可见状态) 
ViewGroup itemView = (ViewGroup) getChildAt(dragPosition 
- getFirstVisiblePosition()); 
// 获取到的dragPoint其实就是在你点击指定item项中的高度. 
dragPoint = y - itemView.getTop(); 
// 这个值是固定的:其实就是ListView这个控件与屏幕最顶部的距离(一般为标题栏+状态栏). 
dragOffset = (int) (ev.getRawY() - y); 
// 获取可拖拽的图标 
View dragger = itemView.findViewById(R.id.iv_drag_list_item_2); 
// x  dragger.getLeft() - 20这句话为了更好的触摸(-20可以省略) 
if (dragger != null && x  dragger.getLeft() - 20) { 
upScrollBounce = getHeight() / 3;// 取得向上滚动的边际,大概为该控件的1/3 
downScrollBounce = getHeight() * 2 / 3;// 取得向下滚动的边际,大概为该控件的2/3 
itemView.setDrawingCacheEnabled(true);// 开启cache. 
Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());// 根据cache创建一个新的bitmap对象. 
startDrag(bm, y);// 初始化影像 
} 
// return false; 
} 
return super.onInterceptTouchEvent(ev); 
} 
这个方法的作用很简单:当我们摁下的如果是可拖拽的图标,那么进行初始化该Item的映像试图.
而在这里如果大家对WindowManager和WindowManager.LayoutParams不熟悉的朋友先去参考下这篇文章,要对WindowManager有一定的了解,简单的会应用.
接下来我们看onTouchEvent事件:
[java]
代码如下:
/** 
* 触摸事件处理 
*/ 
@Override 
public boolean onTouchEvent(MotionEvent ev) { 
// item的view不为空,且获取的dragPosition有效 
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; 
case MotionEvent.ACTION_DOWN: 
break; 
default: 
break; 
} 
return true;// 取消ListView滑动. 
} 
return super.onTouchEvent(ev); 
} 
简单说明:首先在Touch中,我们要进行判断,是否点击的是拖动图标,如果是的话,那么对ACTION_MOVE and ACTION_UP相应事件进行处理,并且返回true or false.作用:取消ListView自身的Touch事件.如果不是的话,执行ListView 本身的Touch事件.
大致就介绍这么多,具体的实现,还是大家看源码吧,我注释的还算清晰,只要大家仔细看的话,一定可以掌握的,为什么这么说呢,技术只有在掌握了情况下才可以进行拓展.
对了,提醒大家要理解这三句话:
getRawX()和getRawY():获得的是相对屏幕的位置.
getX()和getY():获得的永远是相对view的触摸位置 坐标(这两个值不会超过view的长度和宽度)。
getLeft , getTop, getBottom,getRight, 这个指的是该控件相对于父控件的距离.
源码:
[java] 
代码如下:
package com.jj.drag; 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.os.AsyncTask; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.Gravity; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.ViewConfiguration; 
import android.view.ViewGroup; 
import android.view.WindowManager; 
import android.widget.AbsListView; 
import android.widget.AbsListView.OnScrollListener; 
import android.widget.AdapterView; 
import android.widget.ImageView; 
import android.widget.ListView; 
import com.jj.drag.MainActivity.DragListAdapter; 
/*** 
* 自定义拖拽ListView 
* 
* @author zhangjia 
* 
*/ 
public class DragListView extends ListView { 
private WindowManager windowManager;// windows窗口控制类 
private WindowManager.LayoutParams windowParams;// 用于控制拖拽项的显示的参数 
private int scaledTouchSlop;// 判断滑动的一个距离,scroll的时候会用到(24) 
private ImageView dragImageView;// 被拖拽的项(item),其实就是一个ImageView 
private int dragSrcPosition;// 手指拖动项原始在列表中的位置 
private int dragPosition;// 手指点击准备拖动的时候,当前拖动项在列表中的位置. 
private int dragPoint;// 在当前数据项中的位置 
private int dragOffset;// 当前视图和屏幕的距离(这里只使用了y方向上) 
private int upScrollBounce;// 拖动的时候,开始向上滚动的边界 
private int downScrollBounce;// 拖动的时候,开始向下滚动的边界 
private final static int step = 1;// ListView 滑动步伐. 
private int current_Step;// 当前步伐. 
/*** 
* 构造方法 
* 
* @param context 
* @param attrs 
*/ 
public DragListView(Context context, AttributeSet attrs) { 
super(context, attrs); 
} 
/*** 
* touch事件拦截 
*/ 
@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) { 
// 按下 
if (ev.getAction() == MotionEvent.ACTION_DOWN) { 
int x = (int) ev.getX();// 获取相对与ListView的x坐标 
int y = (int) ev.getY();// 获取相应与ListView的y坐标 
dragSrcPosition = dragPosition = pointToPosition(x, y); 
// 无效不进行处理 
if (dragPosition == AdapterView.INVALID_POSITION) { 
return super.onInterceptTouchEvent(ev); 
} 
// 获取当前位置的视图(可见状态) 
ViewGroup itemView = (ViewGroup) getChildAt(dragPosition 
- getFirstVisiblePosition()); 
// 获取到的dragPoint其实就是在你点击指定item项中的高度. 
dragPoint = y - itemView.getTop(); 
// 这个值是固定的:其实就是ListView这个控件与屏幕最顶部的距离(一般为标题栏+状态栏). 
dragOffset = (int) (ev.getRawY() - y); 
// 获取可拖拽的图标 
View dragger = itemView.findViewById(R.id.iv_drag_list_item_2); 
// x  dragger.getLeft() - 20这句话为了更好的触摸(-20可以省略) 
if (dragger != null && x  dragger.getLeft() - 20) { 
upScrollBounce = getHeight() / 3;// 取得向上滚动的边际,大概为该控件的1/3 
downScrollBounce = getHeight() * 2 / 3;// 取得向下滚动的边际,大概为该控件的2/3 
itemView.setDrawingCacheEnabled(true);// 开启cache. 
Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());// 根据cache创建一个新的bitmap对象. 
startDrag(bm, y);// 初始化影像 
} 
} 
return super.onInterceptTouchEvent(ev); 
} 
/** 
* 触摸事件处理 
*/ 
@Override 
public boolean onTouchEvent(MotionEvent ev) { 
// item的view不为空,且获取的dragPosition有效 
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; 
case MotionEvent.ACTION_DOWN: 
break; 
default: 
break; 
} 
return true;// 取消ListView滑动. 
} 
return super.onTouchEvent(ev); 
} 
/** 
* 准备拖动,初始化拖动项的图像 
* 
* @param bm 
* @param y 
*/ 
private void startDrag(Bitmap bm, int y) { 
// stopDrag(); 
/*** 
* 初始化window. 
*/ 
windowParams = new WindowManager.LayoutParams(); 
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;// 窗口所使用的动画设置 
ImageView imageView = new ImageView(getContext()); 
imageView.setImageBitmap(bm); 
windowManager = (WindowManager) getContext().getSystemService("window"); 
windowManager.addView(imageView, windowParams); 
dragImageView = imageView; 
} 
/** 
* 拖动执行,在Move方法中执行 
* 
* @param y 
*/ 
public void onDrag(int y) { 
int drag_top = y - dragPoint;// 拖拽view的top值不能<0,否则则出界. 
if (dragImageView != null && drag_top = 0) { 
windowParams.alpha = 0.5f;// 透明度 
windowParams.y = y - dragPoint + dragOffset;// 移动y值.//记得要加上dragOffset,windowManager计算的是整个屏幕.(标题栏和状态栏都要算上) 
windowManager.updateViewLayout(dragImageView, windowParams);// 时时移动. 
} 
// 为了避免滑动到分割线的时候,返回-1的问题 
int tempPosition = pointToPosition(0, y); 
if (tempPosition != INVALID_POSITION) { 
dragPosition = tempPosition; 
} 
doScroller(y); 
} 
/*** 
* ListView的移动. 
* 要明白移动原理:当映像移动到下端的时候,ListView向上滑动,当映像移动到上端的时候,ListView要向下滑动。正好和实际的相反. 
* 
*/ 
public void doScroller(int y) { 
Log.e("jj", "y=" + y); 
Log.e("jj", "upScrollBounce=" + upScrollBounce); 
// ListView需要下滑 
if (y  upScrollBounce) { 
current_Step = step + (upScrollBounce - y) / 10;// 时时步伐 
}// ListView需要上滑 
else if (y  downScrollBounce) { 
current_Step = -(step + (y - downScrollBounce)) / 10;// 时时步伐 
} else { 
current_Step = 0; 
} 
// 获取你拖拽滑动到位置及显示item相应的view上(注:可显示部分)(position) 
View view = getChildAt(dragPosition - getFirstVisiblePosition()); 
// 真正滚动的方法setSelectionFromTop() 
setSelectionFromTop(dragPosition, view.getTop() + current_Step); 
} 
/** 
* 停止拖动,删除影像 
*/ 
public void stopDrag() { 
if (dragImageView != null) { 
windowManager.removeView(dragImageView); 
dragImageView = null; 
} 
} 
/** 
* 拖动放下的时候 
* 
* @param y 
*/ 
public void onDrop(int y) { 
// 为了避免滑动到分割线的时候,返回-1的问题 
int tempPosition = pointToPosition(0, y); 
if (tempPosition != INVALID_POSITION) { 
dragPosition = tempPosition; 
} 
// 超出边界处理(如果向上超过第二项Top的话,那么就放置在第一个位置) 
if (y  getChildAt(0).getTop()) { 
// 超出上边界 
dragPosition = 0; 
// 如果拖动超过最后一项的最下边那么就防止在最下边 
} else if (y  getChildAt(getChildCount() - 1).getBottom()) { 
// 超出下边界 
dragPosition = getAdapter().getCount() - 1; 
} 
// 数据交换 
if (dragPosition  getAdapter().getCount()) { 
DragListAdapter adapter = (DragListAdapter) getAdapter(); 
adapter.update(dragSrcPosition, dragPosition); 
} 
} 
}
 
下面我说下适配器:
[java] 
代码如下:
/*** 
* 自定义适配器 
* 
* @author zhangjia 
* 
*/ 
class DragListAdapter extends BaseAdapter { 
private ArrayListString arrayTitles; 
private ArrayListInteger arrayDrawables; 
private Context context; 
public DragListAdapter(Context context, ArrayListString arrayTitles, 
ArrayListInteger arrayDrawables) { 
this.context = context; 
this.arrayTitles = arrayTitles; 
this.arrayDrawables = arrayDrawables; 
} 
@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
View view = convertView; 
/*** 
* 在这里尽可能每次都进行实例化新的,这样在拖拽ListView的时候不会出现错乱. 
* 具体原因不明,不过这样经过测试,目前没有发现错乱。虽说效率不高,但是做拖拽LisView足够了。 
*/ 
view = LayoutInflater.from(context).inflate( 
R.layout.drag_list_item, null); 
TextView textView = (TextView) view 
.findViewById(R.id.tv_drag_list_item_text); 
ImageView imageView = (ImageView) view 
.findViewById(R.id.iv_drag_list_item_1); 
imageView.setImageResource(arrayDrawables.get(position)); 
textView.setText(arrayTitles.get(position)); 
return view; 
} 
/*** 
* 动态修改ListVIiw的方位. 
* 
* @param start 
* 点击移动的position 
* @param down 
* 松开时候的position 
*/ 
public void update(int start, int down) { 
// 获取删除的东东. 
String title = arrayTitles.get(start); 
int drawable_id = arrayDrawables.get(start); 
arrayTitles.remove(start);// 删除该项 
arrayDrawables.remove(start);// 删除该项 
arrayTitles.add(down, title);// 添加删除项 
arrayDrawables.add(down, drawable_id);// 添加删除项 
notifyDataSetChanged();// 刷新ListView 
} 
@Override 
public int getCount() { 
return Title.length; 
} 
@Override 
public Object getItem(int position) { 
return Title[position]; 
} 
@Override 
public long getItemId(int position) { 
return position; 
} 
} 
这里不过多解释了,相信大家都看的明白.如果疑问请留言.
展示下运行效果:
效果看起来还行吧,如果觉得不错的话,记得要赞一个哦.
下面我们接着修改,模拟百度嘛,谁让百度这么牛叉呢.
思路:点中拖拉图标的时候,每次移动只要dragPosition发生改变,也就是我移动到了下一个位置,那么此时我就进行交换执行update.并且除了第一次移动外,在每次交换后要除去映射源的显示,这样用户觉得这里的空位就是就是为我准备的,比较人性化.
实现起来并不复杂,前提是你得掌握上面的操作.
源码如下;
[java]
代码如下:
package com.jj.drag; 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.Color; 
import android.os.AsyncTask; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.Gravity; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.ViewConfiguration; 
import android.view.ViewGroup; 
import android.view.WindowManager; 
import android.widget.AbsListView; 
import android.widget.AbsListView.OnScrollListener; 
import android.widget.AdapterView; 
import android.widget.ImageView; 
import android.widget.ListView; 
import com.jj.drag.MainActivity.DragListAdapter; 
public class DragListView extends ListView { 
private WindowManager windowManager;// windows窗口控制类 
private WindowManager.LayoutParams windowParams;// 用于控制拖拽项的显示的参数 
private int scaledTouchSlop;// 判断滑动的一个距离,scroll的时候会用到(24) 
private ImageView dragImageView;// 被拖拽的项(item),其实就是一个ImageView 
private int dragSrcPosition;// 手指拖动项原始在列表中的位置 
private int dragPosition;// 手指点击准备拖动的时候,当前拖动项在列表中的位置. 
private int dragPoint;// 在当前数据项中的位置 
private int dragOffset;// 当前视图和屏幕的距离(这里只使用了y方向上) 
private int upScrollBounce;// 拖动的时候,开始向上滚动的边界 
private int downScrollBounce;// 拖动的时候,开始向下滚动的边界 
private final static int step = 1;// ListView 滑动步伐. 
private int current_Step;// 当前步伐. 
private int temChangId;// 临时交换id 
private boolean isLock;// 是否上锁. 
public void setLock(boolean isLock) { 
this.isLock = isLock; 
} 
public DragListView(Context context, AttributeSet attrs) { 
super(context, attrs); 
scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 
} 
/*** 
* touch事件拦截 在这里我进行相应拦截, 
*/ 
@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) { 
// 按下 
if (ev.getAction() == MotionEvent.ACTION_DOWN && !isLock) { 
int x = (int) ev.getX();// 获取相对与ListView的x坐标 
int y = (int) ev.getY();// 获取相应与ListView的y坐标 
temChangId = dragSrcPosition = dragPosition = pointToPosition(x, y); 
// 无效不进行处理 
if (dragPosition == AdapterView.INVALID_POSITION) { 
return super.onInterceptTouchEvent(ev); 
} 
// 获取当前位置的视图(可见状态) 
ViewGroup itemView = (ViewGroup) getChildAt(dragPosition 
- getFirstVisiblePosition()); 
// 获取到的dragPoint其实就是在你点击指定item项中的高度. 
dragPoint = y - itemView.getTop(); 
// 这个值是固定的:其实就是ListView这个控件与屏幕最顶部的距离(一般为标题栏+状态栏). 
dragOffset = (int) (ev.getRawY() - y); 
// 获取可拖拽的图标 
View dragger = itemView.findViewById(R.id.iv_drag_list_item_2); 
// x  dragger.getLeft() - 20这句话为了更好的触摸(-20可以省略) 
if (dragger != null && x  dragger.getLeft() - 20) { 
upScrollBounce = getHeight() / 3;// 取得向上滚动的边际,大概为该控件的1/3 
downScrollBounce = getHeight() * 2 / 3;// 取得向下滚动的边际,大概为该控件的2/3 
itemView.setBackgroundColor(Color.BLUE); 
itemView.setDrawingCacheEnabled(true);// 开启cache. 
Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());// 根据cache创建一个新的bitmap对象. 
startDrag(bm, y);// 初始化影像 
} 
return false; 
} 
return super.onInterceptTouchEvent(ev); 
} 
/** 
* 触摸事件处理 
*/ 
@Override 
public boolean onTouchEvent(MotionEvent ev) { 
// item的view不为空,且获取的dragPosition有效 
if (dragImageView != null && dragPosition != INVALID_POSITION 
&& !isLock) { 
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; 
case MotionEvent.ACTION_DOWN: 
break; 
default: 
break; 
} 
return true;// 取消ListView滑动. 
} 
return super.onTouchEvent(ev); 
} 
/** 
* 准备拖动,初始化拖动项的图像 
* 
* @param bm 
* @param y 
*/ 
private void startDrag(Bitmap bm, int y) { 
// stopDrag(); 
/*** 
* 初始化window. 
*/ 
windowParams = new WindowManager.LayoutParams(); 
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;// 窗口所使用的动画设置 
ImageView imageView = new ImageView(getContext()); 
imageView.setImageBitmap(bm); 
windowManager = (WindowManager) getContext().getSystemService("window"); 
windowManager.addView(imageView, windowParams); 
dragImageView = imageView; 
} 
/** 
* 拖动执行,在Move方法中执行 
* 
* @param y 
*/ 
public void onDrag(int y) { 
int drag_top = y - dragPoint;// 拖拽view的top值不能<0,否则则出界. 
if (dragImageView != null && drag_top = 0) { 
windowParams.alpha = 0.5f; 
windowParams.y = y - dragPoint + dragOffset; 
windowManager.updateViewLayout(dragImageView, windowParams);// 时时移动. 
} 
// 为了避免滑动到分割线的时候,返回-1的问题 
int tempPosition = pointToPosition(0, y); 
if (tempPosition != INVALID_POSITION) { 
dragPosition = tempPosition; 
} 
onChange(y);// 时时交换 
doScroller(y);// listview移动. 
} 
/*** 
* ListView的移动. 
* 要明白移动原理:当我移动到下端的时候,ListView向上滑动,当我移动到上端的时候,ListView要向下滑动。正好和实际的相反. 
* 
*/ 
public void doScroller(int y) { 
// Log.e("jj", "y=" + y); 
// Log.e("jj", "upScrollBounce=" + upScrollBounce); 
// ListView需要下滑 
if (y  upScrollBounce) { 
current_Step = step + (upScrollBounce - y) / 10;// 时时步伐 
}// ListView需要上滑 
else if (y  downScrollBounce) { 
current_Step = -(step + (y - downScrollBounce)) / 10;// 时时步伐 
} else { 
current_Step = 0; 
} 
// 获取你拖拽滑动到位置及显示item相应的view上(注:可显示部分)(position) 
View view = getChildAt(dragPosition - getFirstVisiblePosition()); 
// 真正滚动的方法setSelectionFromTop() 
setSelectionFromTop(dragPosition, view.getTop() + current_Step); 
} 
/** 
* 停止拖动,删除影像 
*/ 
public void stopDrag() { 
if (dragImageView != null) { 
windowManager.removeView(dragImageView); 
dragImageView = null; 
} 
} 
/*** 
* 拖动时时change 
*/ 
private void onChange(int y) { 
// 数据交换 
if (dragPosition  getAdapter().getCount()) { 
DragListAdapter adapter = (DragListAdapter) getAdapter(); 
adapter.isHidden = false; 
if (dragPosition != temChangId) { 
adapter.update(temChangId, dragPosition); 
temChangId = dragPosition;// 将点击最初所在位置position付给临时的,用于判断是否换位. 
} 
} 
// 为了避免滑动到分割线的时候,返回-1的问题 
int tempPosition = pointToPosition(0, y); 
if (tempPosition != INVALID_POSITION) { 
dragPosition = tempPosition; 
} 
// 超出边界处理(如果向上超过第二项Top的话,那么就放置在第一个位置) 
if (y  getChildAt(0).getTop()) { 
// 超出上边界 
dragPosition = 0; 
// 如果拖动超过最后一项的最下边那么就防止在最下边 
} else if (y  getChildAt(getChildCount() - 1).getBottom()) { 
// 超出下边界 
dragPosition = getAdapter().getCount() - 1; 
} 
} 
/** 
* 拖动放下的时候 
* 
* @param y 
*/ 
public void onDrop(int y) { 
// 数据交换 
if (dragPosition  getAdapter().getCount()) { 
DragListAdapter adapter = (DragListAdapter) getAdapter(); 
adapter.isHidden = false; 
adapter.notifyDataSetChanged();// 刷新. 
} 
} 
} 
因为我们要时时交换位置,所以将原先的拖动方法onDrop方法移动到onChange中.具体的还是看源码吧.
另外的就是对适配器的修改,因为你要对特殊的item进行隐藏之类的操作,这些代码我就不写了,我会将案例上传网上,不懂的可以下载源码.
好了还是我们来观看下效果吧.
怎么样,这个效果看起来要比上面那个效果更人性化点吧,我的操作或许有点快,不信的话,你自己手机体验一下吧.
关于ListView拖拽就说到这里,如有不足请大家自己创新.
下面我们接着对GridView的拖拽简单说明.因为这些在项目中我们都会用到,所以既然做到就做全面点吧.好了大家接着往下看吧.
首先说明,原理一样,都是拖动映像,记录拖动位置,然后调用notifyDataSetChanged更新UI.
而GridView不同的是你要根据x,y值共同获取点击的position和移动至的position,而ListView因为不涉及x坐标.
嗯,最初的原始移动我就不给大家展示了,效果也不是很友好,我直接展示时时更新的那种方法.效果类是与上面那个时时更新ListView一样。
原理也一样.下面我们直接看代码吧.
[java]
代码如下:
package com.jj.draggrid; 
import java.util.logging.Handler; 
import com.jj.draggrid.MainActivity.DragGridAdapter; 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.PixelFormat; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.Gravity; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.ViewGroup; 
import android.view.WindowManager; 
import android.widget.AdapterView; 
import android.widget.BaseAdapter; 
import android.widget.GridView; 
import android.widget.ImageView; 
import android.widget.Toast; 
/*** 
* 自定义拖拽GridView 
* 
* @author zhangjia 
* 
*/ 
public class DragGridView extends GridView { 
private WindowManager windowManager;// windows窗口控制类 
private WindowManager.LayoutParams windowParams;// 用于控制拖拽项的显示的参数 
private int scaledTouchSlop;// 判断滑动的一个距离,scroll的时候会用到(24) 
private ImageView dragImageView;// 被拖拽的项(item),其实就是一个ImageView 
private int dragSrcPosition;// 手指拖动项原始在列表中的位置 
private int dragPosition;// 手指点击准备拖动的时候,当前拖动项在列表中的位置. 
private int dragPointX;// 在当前数据项中的位置 
private int dragPointY;// 在当前数据项中的位置 
private int dragOffsetX;// 当前视图和屏幕的距离(这里只使用了x方向上) 
private int dragOffsetY;// 当前视图和屏幕的距离(这里只使用了y方向上) 
private int upScrollBounce;// 拖动的时候,开始向上滚动的边界 
private int downScrollBounce;// 拖动的时候,开始向下滚动的边界 
private int temChangId;// 临时交换id 
private boolean isDoTouch = false;// touch是否可用 
private boolean isHide = false;// 是否隐藏 
private Handler handler; 
public void setDoTouch(boolean isDoTouch) { 
this.isDoTouch = isDoTouch; 
} 
public DragGridView(Context context, AttributeSet attrs) { 
super(context, attrs); 
} 
@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) { 
if (ev.getAction() == MotionEvent.ACTION_DOWN) { 
int x = (int) ev.getX(); 
int y = (int) ev.getY(); 
temChangId = dragSrcPosition = dragPosition = pointToPosition(x, y); 
if (dragPosition == AdapterView.INVALID_POSITION) { 
return super.onInterceptTouchEvent(ev); 
} 
ViewGroup itemView = (ViewGroup) getChildAt(dragPosition 
- getFirstVisiblePosition()); 
dragPointX = x - itemView.getLeft(); 
dragPointY = y - itemView.getTop(); 
dragOffsetX = (int) (ev.getRawX() - x); 
dragOffsetY = (int) (ev.getRawY() - y); 
View dragger = itemView.findViewById(R.id.drag_grid_item); 
/*** 
* 判断是否选中拖动图标 
*/ 
if (dragger != null && dragPointX  dragger.getLeft() 
&& dragPointX  dragger.getRight() 
&& dragPointY  dragger.getTop() 
&& dragPointY  dragger.getBottom() + 20) { 
upScrollBounce = getHeight() / 4; 
downScrollBounce = getHeight() * 3 / 4; 
itemView.setDrawingCacheEnabled(true); 
Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache()); 
startDrag(bm, x, y);// 初始话映像 
dragger.setVisibility(View.INVISIBLE);// 隐藏该项. 
} 
} 
return super.onInterceptTouchEvent(ev); 
} 
@Override 
public boolean onTouchEvent(MotionEvent ev) { 
if (dragImageView != null && dragPosition != INVALID_POSITION 
&& isDoTouch) { 
int action = ev.getAction(); 
switch (action) { 
/*** 
* 
*/ 
case MotionEvent.ACTION_UP: 
int upX = (int) ev.getX(); 
int upY = (int) ev.getY(); 
stopDrag();// 删除映像 
onDrop(upX, upY);// 松开 
// isDoTouch = false; 
break; 
/*** 
* 拖拽item 
* 
*/ 
case MotionEvent.ACTION_MOVE: 
int moveX = (int) ev.getX(); 
int moveY = (int) ev.getY(); 
onDrag(moveX, moveY);// 拖拽 
break; 
case MotionEvent.ACTION_DOWN: 
int downX = (int) ev.getX(); 
int downY = (int) ev.getY(); 
onHide(downX, downY);// 隐藏该项 
break; 
default: 
break; 
} 
return true; 
} 
return super.onTouchEvent(ev); 
} 
/** 
* 准备拖动,初始化拖动项的图像 
* 
* @param bm 
* @param y 
*/ 
public void startDrag(Bitmap bm, int x, int y) { 
windowParams = new WindowManager.LayoutParams(); 
windowParams.gravity = Gravity.TOP | Gravity.LEFT; 
windowParams.x = x - dragPointX + dragOffsetX; 
windowParams.y = y - dragPointY + dragOffsetY; 
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.windowAnimations = 0; 
ImageView imageView = new ImageView(getContext()); 
imageView.setImageBitmap(bm); 
windowManager = (WindowManager) getContext().getSystemService("window"); 
windowManager.addView(imageView, windowParams); 
dragImageView = imageView; 
} 
/*** 
* 拖动时时change 
*/ 
private void onChange(int x, int y) { 
// 获取适配器 
DragGridAdapter adapter = (DragGridAdapter) getAdapter(); 
// 数据交换 
if (dragPosition  getAdapter().getCount()) { 
// 不相等的情况下要进行换位,相等的情况下说明正在移动 
if (dragPosition != temChangId) { 
adapter.update(temChangId, dragPosition);// 进行换位 
temChangId = dragPosition;// 将点击最初所在位置position付给临时的,用于判断是否换位. 
} 
} 
// 为了避免滑动到分割线的时候,返回-1的问题 
int tempPosition = pointToPosition(x, y); 
if (tempPosition != INVALID_POSITION) { 
dragPosition = tempPosition; 
} 
} 
/*** 
* 拖动执行,在Move方法中执行 
* 
* @param x 
* @param y 
*/ 
public void onDrag(int x, int y) { 
// 移动 
if (dragImageView != null) { 
windowParams.alpha = 0.8f; 
windowParams.x = x - dragPointX + dragOffsetX; 
windowParams.y = y - dragPointY + dragOffsetY; 
windowManager.updateViewLayout(dragImageView, windowParams); 
} 
onChange(x, y);// 时时交换 
// 滚动 
if (y  upScrollBounce || y  downScrollBounce) { 
// 使用setSelection来实现滚动 
setSelection(dragPosition); 
} 
} 
/*** 
* 隐藏该选项 
*/ 
private void onHide(int x, int y) { 
// 获取适配器 
DragGridAdapter adapter = (DragGridAdapter) getAdapter(); 
// 为了避免滑动到分割线的时候,返回-1的问题 
int tempPosition = pointToPosition(x, y); 
if (tempPosition != INVALID_POSITION) { 
dragPosition = tempPosition; 
} 
adapter.setIsHidePosition(dragPosition); 
} 
/** 
* 停止拖动,删除影像 
*/ 
public void stopDrag() { 
if (dragImageView != null) { 
windowManager.removeView(dragImageView); 
dragImageView = null; 
} 
} 
/*** 
* 拖动放下的时候 
* 
* @param x 
* @param y 
*/ 
public void onDrop(int x, int y) { 
DragGridAdapter adapter = (DragGridAdapter) getAdapter(); 
adapter.setIsHidePosition(-1);// 不进行隐藏 
} 
} 
来源:http://www.tulaoshi.com/n/20160219/1596959.html
看过《android ListView和GridView拖拽移位实现代码》的人还看了以下文章 更多>>