android ListView和GridView拖拽移位实现代码
关于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 arraylist<string> arraytitles;
private arraylist<integer> arraydrawables;
private context context;
public draglistadapter(context context, arraylist<string> arraytitles,
arraylist<integer> 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);// 不进行隐藏
}
}