服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - android ListView和GridView拖拽移位实现代码

android ListView和GridView拖拽移位实现代码

2020-12-23 15:07Android教程网 Android

有些朋友对android中ListView和GridView拖拽移位功能的实现不是很了解,接下来将详细介绍,需要了解的朋友可以参考下

关于listview拖拽移动位置,想必大家并不陌生,比较不错的软件都用到如此功能了.如:搜狐,网易,百度等,但是相比来说还是百度的用户体验较好,不偏心了,下面看几个示例:
android ListView和GridView拖拽移位实现代码      android ListView和GridView拖拽移位实现代码      android ListView和GridView拖拽移位实现代码

首先说一下:拖拽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);
}

}

}


下面我说下适配器:

  1. /*** 
  2. * 自定义适配器 
  3. * 
  4. * @author zhangjia 
  5. * 
  6. */ 
  7. class draglistadapter extends baseadapter { 
  8. private arraylist<string> arraytitles; 
  9. private arraylist<integer> arraydrawables; 
  10. private context context; 
  11.  
  12. public draglistadapter(context context, arraylist<string> arraytitles, 
  13. arraylist<integer> arraydrawables) { 
  14. this.context = context; 
  15. this.arraytitles = arraytitles; 
  16. this.arraydrawables = arraydrawables; 
  17.  
  18. @override 
  19. public view getview(int position, view convertview, viewgroup parent) { 
  20. view view = convertview; 
  21. /*** 
  22. * 在这里尽可能每次都进行实例化新的,这样在拖拽listview的时候不会出现错乱. 
  23. * 具体原因不明,不过这样经过测试,目前没有发现错乱。虽说效率不高,但是做拖拽lisview足够了。 
  24. */ 
  25. view = layoutinflater.from(context).inflate( 
  26. r.layout.drag_list_item, null); 
  27.  
  28. textview textview = (textview) view 
  29. .findviewbyid(r.id.tv_drag_list_item_text); 
  30. imageview imageview = (imageview) view 
  31. .findviewbyid(r.id.iv_drag_list_item_1); 
  32. imageview.setimageresource(arraydrawables.get(position)); 
  33. textview.settext(arraytitles.get(position)); 
  34. return view; 
  35.  
  36. /*** 
  37. * 动态修改listviiw的方位. 
  38. * 
  39. * @param start 
  40. * 点击移动的position 
  41. * @param down 
  42. * 松开时候的position 
  43. */ 
  44. public void update(int start, int down) { 
  45. // 获取删除的东东. 
  46. string title = arraytitles.get(start); 
  47. int drawable_id = arraydrawables.get(start); 
  48.  
  49. arraytitles.remove(start);// 删除该项 
  50. arraydrawables.remove(start);// 删除该项 
  51.  
  52. arraytitles.add(down, title);// 添加删除项 
  53. arraydrawables.add(down, drawable_id);// 添加删除项 
  54.  
  55. notifydatasetchanged();// 刷新listview 
  56.  
  57. @override 
  58. public int getcount() { 
  59.  
  60. return title.length; 
  61.  
  62. @override 
  63. public object getitem(int position) { 
  64. return title[position]; 
  65.  
  66. @override 
  67. public long getitemid(int position) { 
  68. return position; 
  69.  

这里不过多解释了,相信大家都看的明白.如果疑问请留言.
展示下运行效果:
android ListView和GridView拖拽移位实现代码

 

效果看起来还行吧,如果觉得不错的话,记得要赞一个哦.

下面我们接着修改,模拟百度嘛,谁让百度这么牛叉呢.
思路:点中拖拉图标的时候,每次移动只要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进行隐藏之类的操作,这些代码我就不写了,我会将案例上传网上,不懂的可以.
好了还是我们来观看下效果吧.
android ListView和GridView拖拽移位实现代码

 

怎么样,这个效果看起来要比上面那个效果更人性化点吧,我的操作或许有点快,不信的话,你自己手机体验一下吧.
关于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);// 不进行隐藏

}

}

延伸 · 阅读

精彩推荐