Android 仿网易新闻客户端分类排序功能
先来看看网易新闻客户端以及自己实现的效果图,效果当然还是网易的好
gridviewsort.gif
如何实现拖拽一个item
用windowmanager添加一个imageview,并且将这个imageview的显示图片设置成被拖拽item的截图,截图可以通过view的getdrawingcache获得。拖拽的时候,隐藏原始的item。处理触摸事件的actionmove,调整imageview的位置,跟随手指移动。在actionup的时候removeview
gridview
@override public boolean onitemlongclick(adapterview<?> adapterview, view view, int i, long l) { // 至少有两个item的时候,才有排序 if (getchildcount() >= 2) { mview = view; // 在调用getdrawingcache必须先调用 view.setdrawingcacheenabled(true); // 获取截图并设置 bitmap bitmap = view.getdrawingcache(); mdragitemview.setimagebitmap(bitmap); // 设置拖拽的imageview的params mdragitemlayoutparams.gravity = gravity.top | gravity.left; mdragitemlayoutparams.width = bitmap.getwidth(); mdragitemlayoutparams.height = bitmap.getheight(); mdragitemlayoutparams.x = (mdownx - mdragitemlayoutparams.width / 2); mdragitemlayoutparams.y = (mdowny - mdragitemlayoutparams.height / 2); // 设置拖拽imageview的中心位于长按点击点 mdragitemlayoutparams.flags = windowmanager.layoutparams.flag_not_focusable //不接受按键事件 | windowmanager.layoutparams.flag_not_touchable // 不接收触摸事件 | windowmanager.layoutparams.flag_keep_screen_on // 保持常亮 | windowmanager.layoutparams.flag_layout_in_screen; // place the window within the entire screen, ignoring decorations around the border (such as the status bar) mdragitemlayoutparams.format = pixelformat.translucent; mdragitemlayoutparams.windowanimations = 0; // 往windowmanager中添加拖拽的view mwindowmanager.addview(mdragitemview, mdragitemlayoutparams); ((gridviewsortadapter) getadapter()).init(); ((gridviewsortadapter) getadapter()).hideview(i); log.d(tag, "long click = " + i); mdragstarted = true; } return true; } @override public boolean ontouchevent(motionevent ev) { switch (ev.getaction() & ev.getactionmasked()) { case motionevent.action_down: mdownx = (int) ev.getrawx(); mdowny = (int) ev.getrawy(); break; case motionevent.action_move: if (mdragstarted) { // 保持中心 mdragitemlayoutparams.x = (int) (ev.getrawx() - mdragitemview.getwidth() / 2); mdragitemlayoutparams.y = (int) (ev.getrawy() - mdragitemview.getheight() / 2); // 更新params mwindowmanager.updateviewlayout(mdragitemview, mdragitemlayoutparams); // ...... } break; case motionevent.action_up: // ...... break; } return super.ontouchevent(ev); }
如何实现隐藏拖拽的item
在开始拖拽的时候,把隐藏的item的position告诉adapter,调用adapter的notifydatasetchanged刷新数据,在getview方法中判断当前的构建的item的position是不是需要隐藏的position是的话就设置view为invisible
gridview
@override public boolean onitemlongclick(adapterview<?> adapterview, view view, int i, long l) { // ...... ((gridviewsortadapter) getadapter()).hideview(i); // ...... } gridviewsortadapter public void hideview(int item) { // ...... mstarthideitemposition = item; notifydatasetchanged(); } private int mstarthideitemposition = adapterview.invalid_position; @override public view getview(int position, view convertview, viewgroup parent) { viewholder holder = null; if (convertview == null) { convertview = layoutinflater.from(mcontext).inflate(r.layout.view_item_grid_view_sort, null); holder = new viewholder(); holder.title = (textview) convertview.findviewbyid(r.id.view_item_grid_view_sort_title); convertview.settag(holder); } else { holder = (viewholder) convertview.gettag(); } holder.title.settext(mtypetitle.get(position)); if (mstarthideitemposition == position) { convertview.setvisibility(view.invisible); } else { convertview.setvisibility(view.visible); } return convertview; }
如何知道当前拖拽到哪一个item之上
要想在拖拽到其他item上面时互换位置,那必须得知道当前拖拽到了哪一个item之上。grideview提供了一个方法叫pointtoposition,可以在处理触摸事件的action_move时,获取手指触摸的x,y来得到当前拖拽到item之上的position。这里需要注意的一点是,在拖拽的过程,同一个item的position是不会变的,除非调用了adapter的notifydatasetchanged,position才会重新计算。比如position为2的item,在拖拽的过程无论怎么动画移动位置,他的position都是2,知道一次拖拽结束,actionup的时候,会调用notifydatasetchanged
gridview
@override public boolean ontouchevent(motionevent ev) { case motionevent.action_move: if (mdragstarted) { // ...... int position = pointtoposition((int) ev.getx(), (int) ev.gety()); // ...... } break; }
如何实现动画
一个item需要水平以及垂直需要移动的距离可以事先先计算出来,其实水平距离不管怎么样一定会是gridview一个单元格的宽度加上水平间距,垂直距离无论如何都是一个单元格的高度加上垂直距离,宽度非常好取,高度的话,这里默认item 的高度和单元格的高度相同。
gridviewsortadapter
view view = mgridview.getchildat(0); mtranslatex = view.getwidth() + mhorizontalspace; mtranslatey = view.getheight() + mverticalspace;
当拖拽到其他item之上时,开始动画
sortgridview
if (position != adapterview.invalid_position && !((gridviewsortadapter) getadapter()).isinanimation()) { log.d(tag, "position = " + position); ((gridviewsortadapter) getadapter()).swap(position); } gridsortadapter public void swap(int position) { manimatorsetlist.clear(); int r_p = mpositionlist.indexof(position); log.d(tag, "r_p = " + r_p); if (mcurrenthideitemposition < r_p) { for (int i = mcurrenthideitemposition + 1; i <= r_p; i++) { view v = mgridview.getchildat(mpositionlist.get(i)); if (i % mcolsnum == 0 && i > 0) { startmoveanimation(v, v.gettranslationx() + mtranslatex * (mcolsnum - 1), v.gettranslationy() - mtranslatey); } else { startmoveanimation(v, v.gettranslationx() - mtranslatex, 0); } } } else if (mcurrenthideitemposition > r_p) { for (int i = r_p; i < mcurrenthideitemposition; i++) { view v = mgridview.getchildat(mpositionlist.get(i)); if ((i + 1) % mcolsnum == 0) { startmoveanimation(v, v.gettranslationx() - mtranslatex * (mcolsnum - 1), v.gettranslationy() + mtranslatey); } else { startmoveanimation(v, v.gettranslationx() + mtranslatex, 0); } } } resetpositionlist(); int value = mpositionlist.get(mstarthideitemposition); if (mstarthideitemposition < r_p) { mpositionlist.add(r_p + 1, value); mpositionlist.remove(mstarthideitemposition); } else if (mstarthideitemposition > r_p) { mpositionlist.add(r_p, value); mpositionlist.remove(mstarthideitemposition + 1); } mcurrenthideitemposition = r_p; } public boolean isinanimation() { return minanimation; } private void resetpositionlist() { mpositionlist.clear(); for (int i = 0; i < mgridview.getchildcount(); i++) { mpositionlist.add(i); } } private void startmoveanimation(view myview, float x, float y) { animatorset set = new animatorset(); set.playtogether( objectanimator.offloat(myview, "translationx", myview.gettranslationx(), x), objectanimator.offloat(myview, "translationy", myview.gettranslationy(), y) ); set.addlistener(new animator.animatorlistener() { @override public void onanimationstart(animator animator) { minanimation = true; } @override public void onanimationend(animator animator) { minanimation = false; } @override public void onanimationcancel(animator animator) { } @override public void onanimationrepeat(animator animator) { } }); manimatorsetlist.add(set); set.setduration(150).start(); }
这里我主要解释一下代码中 mpositionlist这个列表的作用,之前说过一次拖拽的时候,item的position是不会变化的。
假设有一组数据
a b c d
e f g h
i j k l
此时mpositionlist的内容就是 0 1 2 3 4 5 6 7 8 9 10 11 12
现在将c拖拽到g上,拖拽完成之后的数据应该是,未释放手指
a b d e
f g c h
i j k l
此时mpositionlist的内容就是 0 1 2 4 5 6 7 3 8 9 10 11 12
紧接着,继续拖拽c到e上,你会发现调用pointtoposition方法得到的position是5,但是e现在的索引是4
因此你只需要调用
mpositionlist.indexof(pointtoposition(x,y))
就能得到真实的item的position
其他
如果把gridview的列数变成1那么似曾相识啊
gridviewex.gif
源码地址
以上所述是小编给大家介绍的android 仿网易新闻客户端分类排序功能,希望对大家有所帮助