Android自定义View实现可以拖拽的GridView
程序员文章站
2024-03-31 18:15:10
先看看效果图
主要思想:
1、监听触碰事件
2、用windowmanager添加拖曳的图片
3、用collections.swap()交换list数据
自...
先看看效果图
主要思想:
1、监听触碰事件
2、用windowmanager添加拖曳的图片
3、用collections.swap()交换list数据
自定义代码:
public class draggridveiw extends gridview { private final int press_time = 1000;//长按时间 private int mdownx;//触碰时的x坐标 private int mdowny;//触碰时的y坐标 private int mmovex;//移动时的x坐标 private int mmovey;//移动时的y坐标 private int moffset2top;//draggridview距离屏幕顶部的偏移量 private int moffset2left;//draggridview距离屏幕左边的偏移量 private int mpointtoitemtop;//触碰点距离itemview的上边距 private int mpointtoitemleft;//触碰点距离itemview的左边距 private int mstatusheight;//状态栏高度 private boolean isdraging;//是否正在拖曳 private bitmap mbitmap;//itemview的图片 private int mtouchpostiion;//触碰的位置 private view mtouchitemview;//触碰的itemview private vibrator mvibrator;//震动器 private imageview mdragimageview;//拖曳的view private windowmanager mwindowmanager;//窗口管理器 private windowmanager.layoutparams mwindowlayoutparams;//窗口管理器布局 private onchanagelistener onchanagelistener;//交换事件监听器 private handler mhandler = new handler(); public draggridveiw(context context) { this(context, null); } public draggridveiw(context context, attributeset attrs) { this(context, attrs, 0); } public draggridveiw(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); mstatusheight = getstatusheight(context); mvibrator = (vibrator) context.getsystemservice(context.vibrator_service); mwindowmanager = (windowmanager) context.getsystemservice(context.window_service); } @override public boolean dispatchtouchevent(motionevent ev) { switch (ev.getaction()) { case motionevent.action_down: //使用handler延迟dragresponsems执行mlongclickrunnable mhandler.postdelayed(mlongclickrunnable, press_time); mdownx = (int) ev.getx(); mdowny = (int) ev.gety(); //根据按下的x,y坐标获取所点击item的position mtouchpostiion = pointtoposition(mdownx, mdowny); if (mtouchpostiion == adapterview.invalid_position) { return super.dispatchtouchevent(ev); } //根据position获取该item所对应的view mtouchitemview = getchildat(mtouchpostiion - getfirstvisibleposition()); //下面这几个距离大家可以参考我的博客上面的图来理解下 mpointtoitemtop = mdowny - mtouchitemview.gettop(); mpointtoitemleft = mdownx - mtouchitemview.getleft(); moffset2top = (int) (ev.getrawy() - mdowny); moffset2left = (int) (ev.getrawx() - mdownx); //开启mdragitemview绘图缓存 mtouchitemview.setdrawingcacheenabled(true); //获取mdragitemview在缓存中的bitmap对象 mbitmap = bitmap.createbitmap(mtouchitemview.getdrawingcache()); //这一步很关键,释放绘图缓存,避免出现重复的镜像 mtouchitemview.destroydrawingcache(); break; case motionevent.action_move: int movex = (int) ev.getx(); int movey = (int) ev.gety(); //拖曳点超出gridview区域则取消拖曳事件 if (ev.gety() > getheight() || ev.gety() < 0) { onstopdrag(); } //如果我们在按下的item上面移动,只要超过item的边界就移除mrunnable if (!istouchinitem(mtouchitemview, movex, movey)) { mhandler.removecallbacks(mlongclickrunnable); } break; case motionevent.action_up: mhandler.removecallbacks(mlongclickrunnable); break; } return super.dispatchtouchevent(ev); } @override public boolean ontouchevent(motionevent ev) { if (isdraging && mdragimageview != null) { switch (ev.getaction()) { case motionevent.action_move: mmovex = (int) ev.getx(); mmovey = (int) ev.gety(); //拖动item ondragitem(mmovex, mmovey); break; case motionevent.action_up: onstopdrag(); break; } return true; } return super.ontouchevent(ev); } //处理长按事件的线程 private runnable mlongclickrunnable = new runnable() { @override public void run() { isdraging = true; //设置可以拖拽 mvibrator.vibrate(50); //震动一下 mtouchitemview.setvisibility(view.invisible);//隐藏该itemview //根据我们按下的点显示itemview镜像 createdragview(mbitmap, mdownx, mdowny); } }; //添加拖动view private void createdragview(bitmap bitmap, int downx, int downy) { mwindowlayoutparams = new windowmanager.layoutparams(); mwindowlayoutparams.format = pixelformat.translucent; //图片之外的其他地方透明 mwindowlayoutparams.gravity = gravity.top | gravity.left; mwindowlayoutparams.x = downx - mpointtoitemtop + moffset2left; mwindowlayoutparams.y = downy - mpointtoitemtop + moffset2top - mstatusheight; mwindowlayoutparams.alpha = 0.6f; //透明度 mwindowlayoutparams.width = windowmanager.layoutparams.wrap_content; mwindowlayoutparams.height = windowmanager.layoutparams.wrap_content; mwindowlayoutparams.flags = windowmanager.layoutparams.flag_not_focusable | windowmanager.layoutparams.flag_not_touchable; mdragimageview = new imageview(getcontext()); mdragimageview.setimagebitmap(bitmap); mwindowmanager.addview(mdragimageview, mwindowlayoutparams); } private void removedragview() { if (mdragimageview != null) { mwindowmanager.removeview(mdragimageview); mdragimageview = null; } } //是否点击在gridview的item上面 private boolean istouchinitem(view dragview, int x, int y) { int leftoffset = dragview.getleft(); int topoffset = dragview.gettop(); if (x < leftoffset || x > leftoffset + dragview.getwidth()) { return false; } if (y < topoffset || y > topoffset + dragview.getheight()) { return false; } return true; } //拖动事件处理 private void ondragitem(int movex, int movey) { mwindowlayoutparams.x = movex - mpointtoitemleft + moffset2left; mwindowlayoutparams.y = movey - mpointtoitemtop + moffset2top - mstatusheight; mwindowmanager.updateviewlayout(mdragimageview, mwindowlayoutparams); //更新dragview的位置 onswapitem(movex, movey);//item的相互交换 } //交换item,并且控制item之间的显示与隐藏效果 private void onswapitem(int movex, int movey) { //获取我们手指移动到的那个item的position int tempposition = pointtoposition(movex, movey); //假如tempposition 改变了并且tempposition不等于-1,则进行交换 if (tempposition != mtouchpostiion && tempposition != adapterview.invalid_position) { getchildat(tempposition - getfirstvisibleposition()).setvisibility(view.invisible);//拖动到了新的item,新的item隐藏掉 getchildat(mtouchpostiion - getfirstvisibleposition()).setvisibility(view.visible);//之前的item显示出来 if (onchanagelistener != null) { onchanagelistener.onchange(mtouchpostiion, tempposition); } mtouchpostiion = tempposition; } } //停止拖拽我们将之前隐藏的item显示出来,并将dragview移除 private void onstopdrag() { isdraging = false; getchildat(mtouchpostiion - getfirstvisibleposition()).setvisibility(view.visible); removedragview(); } //item交换事件监听 public void setonchangelistener(onchanagelistener onchanagelistener) { this.onchanagelistener = onchanagelistener; } //获取状态栏高度 private int getstatusheight(context context) { int statusheight = 0; rect localrect = new rect(); ((activity) context).getwindow().getdecorview().getwindowvisibledisplayframe(localrect); statusheight = localrect.top; if (0 == statusheight) { class<?> localclass; try { localclass = class.forname("com.android.internal.r$dimen"); object localobject = localclass.newinstance(); int i5 = integer.parseint(localclass.getfield("status_bar_height").get(localobject).tostring()); statusheight = context.getresources().getdimensionpixelsize(i5); } catch (exception e) { e.printstacktrace(); } } return statusheight; } //当item交换位置的时候回调的方法,我们只需要在该方法中实现数据的交换即可 public interface onchanagelistener { public void onchange(int from, int to); } }
使用方法:
list<hashmap<string, object>> datasourcelist = new arraylist<>(); dragveiw = (draggridveiw) findviewbyid(r.id.view_drag); for (int i = 0; i < 8; i++) { hashmap<string, object> itemhashmap = new hashmap<>(); itemhashmap.put("item_image", r.drawable.sample_1); itemhashmap.put("item_text", "拖拽 " + integer.tostring(i)); datasourcelist.add(itemhashmap); } final simpleadapter msimpleadapter = new simpleadapter(this, datasourcelist, r.layout.item_drag, new string[]{"item_image", "item_text"}, new int[]{r.id.item_image, r.id.item_text}); dragveiw.setadapter(msimpleadapter); dragveiw.setonchangelistener(new draggridveiw.onchanagelistener() { @override public void onchange(int from, int to) { hashmap<string, object> temp = datasourcelist.get(from); //这里的处理需要注意下 if (from < to) { for (int i = from; i < to; i++) { collections.swap(datasourcelist, i, i + 1); } } else if (from > to) { for (int i = from; i > to; i--) { collections.swap(datasourcelist, i, i - 1); } } datasourcelist.set(to, temp); msimpleadapter.notifydatasetchanged(); } });
附录:
log.v("-->getwidth", string.valueof(getwidth()));//dragview的宽度 log.v("-->getheight", string.valueof(getheight()));//dragview的高度 log.v("-->getleft", string.valueof(getleft()));//dragview左边距离屏幕左侧的长度 log.v("-->gettop", string.valueof(gettop()));///dragview上边距离屏幕顶部的长度 log.v("-->getrawx", string.valueof(ev.getrawx()));//触碰点相对于屏幕的x坐标 log.v("-->getrawy", string.valueof(ev.getrawy()));//触碰点相对于屏幕的y坐标 log.v("-->getx", string.valueof(ev.getx()));//触碰点相对于dragview的x坐标 log.v("-->gety", string.valueof(ev.gety()));//触碰点相对于dragview的y坐标 log.v("-->getitemwidth", string.valueof(mtouchitemview.getwidth()));//dragview中itemview的宽度 log.v("-->getitemheight", string.valueof(mtouchitemview.getheight()));//dragview中itemview的高度 log.v("-->getitemleft", string.valueof(mtouchitemview.getleft()));//dragview中itemview左边距离dragview左侧的长度 log.v("-->getitemtop", string.valueof(mtouchitemview.gettop()));//dragview中itemview上边距离dragview顶部的长度
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
Android自定义View实现可以拖拽的GridView
-
Android中在GridView网格视图上实现item拖拽交换的方法
-
Android中在GridView网格视图上实现item拖拽交换的方法
-
Android进阶之自定义View(2)高仿钉钉运动步数实现可动的进度圆环(上)
-
Android自定义View实现简单的圆形Progress效果
-
Android自定义View实现简单的圆形Progress效果
-
Android 自定义View实现单击和双击事件的方法
-
Android自定义View实现字母导航栏的代码
-
Android自定义View实现字母导航栏的代码
-
Android 自定义View实现单击和双击事件的方法