网络上关于GridView可拖动的例子已经不少了,包括带动画不带动画的都有一堆,但几乎都是通过继承Android原生控件GridView来扩展的,当然这种实现方式是很容易联想到的,也是最容易实现的。我随便百度了一下,就有一个:​​http://zhangcb666.blog.163.com/blog/static/4696352920124221043837/​​,大家可以参考一下,我这里就不赘述了。

今天跟大家分享另外一种方式,通过继承ViewGroup来实现,我们都知道,ViewGroup可以填充很多个View,因此,我觉得可以类似把GridView的每一个Item填充到我们自定义的ViewGroup中,然后监听长按时间,实现拖动的效果,同时加上动画效果,个人感觉比网上其他实现方式更加简洁和美观,唯一的缺点就是:没有setAdapter的函数,添加的item,需要我们手动add到ViewGroup中,如果item不是特别复杂和繁多,个人觉得也不算什么问题。好了,废话不多说,我们先来看看效果图,第一张是静态效果,第二张是拖动时的效果图。

viewgroup实现item拖动效果_自定义

  

viewgroup实现item拖动效果_ide_02


其实代码也是很简单的,总共就两个类:一个自定义控件DragGridView,还有一个使用的例子MainActivity。

我们先来看看DragGridView的代码部分:



[java] ​​ view plain​​ ​​copy​​


  1. /**
  2.  * 另外一种方式实现动画可拖动item的GridView
  3.  * 
  4.  * @author way
  5.  * 
  6.  */
  7. public class DragGridView extends ViewGroup implements
  8.         View.OnClickListener, View.OnLongClickListener {  
  9. // layout vars
  10. public static float
  11. protected int colCount, childSize, padding, dpi, scroll = 0;  
  12. protected float lastDelta = 0;  
  13. protected Handler handler = new
  14. // dragging vars
  15. protected int dragged = -1, lastX = -1, lastY = -1, lastTarget = -1;  
  16. protected boolean enabled = true, touching = false;  
  17. // anim vars
  18. public static int animT = 150;  
  19. protected ArrayList<Integer> newPositions = new
  20. // listeners
  21. protected
  22. protected
  23. private
  24.   
  25. /**
  26.      * 拖动item的接口
  27.      */
  28. public interface
  29.   
  30. public abstract void onRearrange(int oldIndex, int
  31.     }  
  32.   
  33. // CONSTRUCTOR AND HELPERS
  34. public
  35. super(context, attrs);  
  36.         setListeners();  
  37.         handler.removeCallbacks(updateTask);  
  38. 500);  
  39. true);  
  40.   
  41. new
  42.         ((Activity) context).getWindowManager().getDefaultDisplay()  
  43.                 .getMetrics(metrics);  
  44.         dpi = metrics.densityDpi;  
  45.     }  
  46.   
  47. protected void
  48. this);  
  49. super.setOnClickListener(this);  
  50. this);  
  51.     }  
  52.   
  53. @Override
  54. public void
  55.         secondaryOnClickListener = l;  
  56.     }  
  57.   
  58. protected Runnable updateTask = new
  59. public void
  60. if (dragged != -1) {  
  61. if (lastY < padding * 3 && scroll > 0)  
  62. 20;  
  63. else if (lastY > getBottom() - getTop() - (padding * 3)  
  64.                         && scroll < getMaxScroll())  
  65. 20;  
  66. else if (lastDelta != 0
  67.                 scroll += lastDelta;  
  68. 9;  
  69. if (Math.abs(lastDelta) < .25)  
  70. 0;  
  71.             }  
  72.             clampScroll();  
  73. true, getLeft(), getTop(), getRight(), getBottom());  
  74.   
  75. this, 25);  
  76.         }  
  77.     };  
  78.   
  79. @Override
  80. public void
  81. super.addView(child);  
  82. 1);  
  83.     };  
  84.   
  85. @Override
  86. public void removeViewAt(int
  87. super.removeViewAt(index);  
  88.         newPositions.remove(index);  
  89.     };  
  90.   
  91. // LAYOUT
  92. @Override
  93. protected void onLayout(boolean changed, int l, int t, int r, int
  94. // compute width of view, in dp
  95. float
  96.   
  97. // determine number of columns, at least 2
  98. 2;  
  99. int sub = 240;  
  100. 280;  
  101. while (w > 0) {  
  102.             colCount++;  
  103.             w -= sub;  
  104. 40;  
  105.         }  
  106.   
  107. // determine childSize and padding, in px
  108.         childSize = (r - l) / colCount;  
  109.         childSize = Math.round(childSize * childRatio);  
  110. 1);  
  111.   
  112. for (int i = 0; i < getChildCount(); i++)  
  113. if
  114.                 Point xy = getCoorFromIndex(i);  
  115.                 getChildAt(i).layout(xy.x, xy.y, xy.x + childSize,  
  116.                         xy.y + childSize);  
  117.             }  
  118.     }  
  119.   
  120. @Override
  121. protected int getChildDrawingOrder(int childCount, int
  122. if (dragged == -1)  
  123. return
  124. else if (i == childCount - 1)  
  125. return
  126. else if
  127. return i + 1;  
  128. return
  129.     }  
  130.   
  131. public int getIndexFromCoor(int x, int
  132. int
  133. if (col == -1 || row == -1) // touch is between columns or rows
  134. return -1;  
  135. int
  136. if
  137. return -1;  
  138. return
  139.     }  
  140.   
  141. protected int getColOrRowFromCoor(int
  142.         coor -= padding;  
  143. for (int i = 0; coor > 0; i++) {  
  144. if
  145. return
  146.             coor -= (childSize + padding);  
  147.         }  
  148. return -1;  
  149.     }  
  150.   
  151. protected int getTargetFromCoor(int x, int
  152. if (getColOrRowFromCoor(y + scroll) == -1) // touch is between rows
  153. return -1;  
  154. // if (getIndexFromCoor(x, y) != -1) //touch on top of another visual
  155. // return -1;
  156.   
  157. int leftPos = getIndexFromCoor(x - (childSize / 4), y);  
  158. int rightPos = getIndexFromCoor(x + (childSize / 4), y);  
  159. if (leftPos == -1 && rightPos == -1) // touch is in the middle of
  160. // nowhere
  161. return -1;  
  162. if (leftPos == rightPos) // touch is in the middle of a visual
  163. return -1;  
  164.   
  165. int target = -1;  
  166. if (rightPos > -1)  
  167.             target = rightPos;  
  168. else if (leftPos > -1)  
  169. 1;  
  170. if
  171. return target - 1;  
  172.   
  173. // Toast.makeText(getContext(), "Target: " + target + ".",
  174. // Toast.LENGTH_SHORT).show();
  175. return
  176.     }  
  177.   
  178. protected Point getCoorFromIndex(int
  179. int
  180. int
  181. return new
  182.                 + (childSize + padding) * row - scroll);  
  183.     }  
  184.   
  185. public int
  186. for (int i = 0; i < getChildCount(); i++)  
  187. if
  188. return
  189. return -1;  
  190.     }  
  191.   
  192. // EVENT HANDLERS
  193. public void
  194. if
  195. if (secondaryOnClickListener != null)  
  196.                 secondaryOnClickListener.onClick(view);  
  197. if (onItemClickListener != null && getLastIndex() != -1)  
  198. null,  
  199.                         getChildAt(getLastIndex()), getLastIndex(),  
  200.                         getLastIndex() / colCount);  
  201.         }  
  202.     }  
  203.   
  204. public boolean
  205. if
  206. return false;  
  207. int
  208. if (index != -1) {  
  209.             dragged = index;  
  210.             animateDragged();  
  211. return true;  
  212.         }  
  213. return false;  
  214.     }  
  215.   
  216. public boolean
  217. int
  218. switch
  219. case
  220. true;  
  221. int) event.getX();  
  222. int) event.getY();  
  223. true;  
  224. break;  
  225. case
  226. int delta = lastY - (int) event.getY();  
  227. if (dragged != -1) {  
  228. // change draw location of dragged visual
  229. int x = (int) event.getX(), y = (int) event.getY();  
  230. int l = x - (3 * childSize / 4), t = y - (3 * childSize / 4);  
  231. 3 / 2),  
  232. 3 / 2));  
  233.   
  234. // check for new target hover
  235. int
  236. if
  237. if (target != -1) {  
  238.                         animateGap(target);  
  239.                         lastTarget = target;  
  240.                     }  
  241.                 }  
  242. else
  243.                 scroll += delta;  
  244.                 clampScroll();  
  245. if (Math.abs(delta) > 2)  
  246. false;  
  247. true, getLeft(), getTop(), getRight(), getBottom());  
  248.             }  
  249. int) event.getX();  
  250. int) event.getY();  
  251.             lastDelta = delta;  
  252. break;  
  253. case
  254. if (dragged != -1) {  
  255.                 View v = getChildAt(dragged);  
  256. if (lastTarget != -1)  
  257.                     reorderChildren();  
  258. else
  259.                     Point xy = getCoorFromIndex(dragged);  
  260.                     v.layout(xy.x, xy.y, xy.x + childSize, xy.y + childSize);  
  261.                 }  
  262.                 v.clearAnimation();  
  263. if (v instanceof
  264. 255);  
  265. 1;  
  266. 1;  
  267.             }  
  268. false;  
  269. break;  
  270.         }  
  271. if (dragged != -1)  
  272. return true;  
  273. return false;  
  274.     }  
  275.   
  276. // EVENT HELPERS
  277. protected void
  278.         View v = getChildAt(dragged);  
  279. int x = getCoorFromIndex(dragged).x + childSize / 2, y = getCoorFromIndex(dragged).y  
  280. 2;  
  281. int l = x - (3 * childSize / 4), t = y - (3 * childSize / 4);  
  282. 3 / 2), t + (childSize * 3 / 2));  
  283. new AnimationSet(true);  
  284. new ScaleAnimation(.667f, 1, .667f, 1,  
  285. 3 / 4, childSize * 3 / 4);  
  286.         scale.setDuration(animT);  
  287. new AlphaAnimation(1, .5f);  
  288.         alpha.setDuration(animT);  
  289.   
  290.         animSet.addAnimation(scale);  
  291.         animSet.addAnimation(alpha);  
  292. true);  
  293. true);  
  294.   
  295.         v.clearAnimation();  
  296.         v.startAnimation(animSet);  
  297.     }  
  298.   
  299. protected void animateGap(int
  300. for (int i = 0; i < getChildCount(); i++) {  
  301.             View v = getChildAt(i);  
  302. if
  303. continue;  
  304. int
  305. if (dragged < target && i >= dragged + 1
  306.                 newPos--;  
  307. else if
  308.                 newPos++;  
  309.   
  310. // animate
  311. int
  312. if (newPositions.get(i) != -1)  
  313.                 oldPos = newPositions.get(i);  
  314. if
  315. continue;  
  316.   
  317.             Point oldXY = getCoorFromIndex(oldPos);  
  318.             Point newXY = getCoorFromIndex(newPos);  
  319. new
  320.                     - v.getTop());  
  321. new
  322.                     - v.getTop());  
  323.   
  324. new
  325.                     Animation.ABSOLUTE, oldOffset.x, Animation.ABSOLUTE,  
  326.                     newOffset.x, Animation.ABSOLUTE, oldOffset.y,  
  327.                     Animation.ABSOLUTE, newOffset.y);  
  328.             translate.setDuration(animT);  
  329. true);  
  330. true);  
  331.             v.clearAnimation();  
  332.             v.startAnimation(translate);  
  333.   
  334.             newPositions.set(i, newPos);  
  335.         }  
  336.     }  
  337.   
  338. protected void
  339. // FIGURE OUT HOW TO REORDER CHILDREN WITHOUT REMOVING THEM ALL AND
  340. // RECONSTRUCTING THE LIST!!!
  341. if (onRearrangeListener != null)  
  342.             onRearrangeListener.onRearrange(dragged, lastTarget);  
  343. new
  344. for (int i = 0; i < getChildCount(); i++) {  
  345.             getChildAt(i).clearAnimation();  
  346.             children.add(getChildAt(i));  
  347.         }  
  348.         removeAllViews();  
  349. while
  350. if (lastTarget == children.size()) // dragged and dropped to the
  351. // right of the last element
  352.             {  
  353.                 children.add(children.remove(dragged));  
  354.                 dragged = lastTarget;  
  355. else if (dragged < lastTarget) // shift to the right
  356.             {  
  357. 1);  
  358.                 dragged++;  
  359. else if (dragged > lastTarget) // shift to the left
  360.             {  
  361. 1);  
  362.                 dragged--;  
  363.             }  
  364. for (int i = 0; i < children.size(); i++) {  
  365. 1);  
  366.             addView(children.get(i));  
  367.         }  
  368. true, getLeft(), getTop(), getRight(), getBottom());  
  369.     }  
  370.   
  371. public void
  372. 0;  
  373.     }  
  374.   
  375. public void
  376.         scroll = Integer.MAX_VALUE;  
  377.         clampScroll();  
  378.     }  
  379.   
  380. protected void
  381. int stretch = 3, overreach = getHeight() / 2;  
  382. int
  383. 0);  
  384.   
  385. if
  386.             scroll = -overreach;  
  387. 0;  
  388. else if
  389.             scroll = max + overreach;  
  390. 0;  
  391. else if (scroll < 0) {  
  392. if
  393. 0;  
  394. else if
  395.                 scroll -= scroll / stretch;  
  396. else if
  397. if
  398.                 scroll = max;  
  399. else if
  400.                 scroll += (max - scroll) / stretch;  
  401.         }  
  402.     }  
  403.   
  404. protected int
  405. int rowCount = (int) Math.ceil((double) getChildCount() / colCount), max = rowCount  
  406. 1) * padding - getHeight();  
  407. return
  408.     }  
  409.   
  410. public int
  411. return
  412.     }  
  413.   
  414. // OTHER METHODS
  415. public void
  416. this.onRearrangeListener = l;  
  417.     }  
  418.   
  419. public void
  420. this.onItemClickListener = l;  
  421.     }  
  422. }  



然后是在布局文件中声明:main.xml



[html] ​​ view plain​​ ​​copy​​


  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent" >
  5.   
  6. <com.way.view.DragGridView
  7. android:id="@+id/vgv"
  8. android:layout_width="fill_parent"
  9. android:layout_height="fill_parent"
  10. android:layout_alignParentLeft="true"
  11. android:layout_alignParentTop="true" />
  12.   
  13. <Button
  14. android:id="@+id/add_item_btn"
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:layout_alignParentBottom="true"
  18. android:layout_alignParentLeft="true"
  19. android:text="@string/button1Text" />
  20.   
  21. <Button
  22. android:id="@+id/view_poem_item"
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:layout_alignParentBottom="true"
  26. android:layout_toRightOf="@+id/add_item_btn"
  27. android:text="@string/button2Text" />
  28.   
  29. </RelativeLayout>



最后就可以直接在代码中调用了MainActivity:



[java] ​​ view plain​​ ​​copy​​


  1. /**
  2.  * MainActivity
  3.  * 
  4.  * @author way
  5.  * 
  6.  */
  7. public class MainActivity extends
  8. static Random random = new
  9. static String[] words = "我 是 一 只 大 笨 猪".split(" ");  
  10.     DragGridView mDragGridView;  
  11.     Button mAddBtn, mViewBtn;  
  12. new
  13.   
  14. @Override
  15. public void
  16. super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.main);  
  18.   
  19.         mDragGridView = ((DragGridView) findViewById(R.id.vgv));  
  20.         mAddBtn = ((Button) findViewById(R.id.add_item_btn));  
  21.         mViewBtn = ((Button) findViewById(R.id.view_poem_item));  
  22.   
  23.         setListeners();  
  24.     }  
  25.   
  26. private void
  27. new
  28. public void onRearrange(int oldIndex, int
  29.                 String word = poem.remove(oldIndex);  
  30. if
  31.                     poem.add(newIndex, word);  
  32. else
  33.                     poem.add(newIndex, word);  
  34.             }  
  35.         });  
  36. new
  37. @Override
  38. public void onItemClick(AdapterView<?> arg0, View arg1, int
  39. long
  40.                 mDragGridView.removeViewAt(arg2);  
  41.                 poem.remove(arg2);  
  42.             }  
  43.         });  
  44. new
  45. public void
  46.                 String word = words[random.nextInt(words.length)];  
  47. new ImageView(MainActivity.this);  
  48.                 view.setImageBitmap(getThumb(word));  
  49.                 mDragGridView.addView(view);  
  50.                 poem.add(word);  
  51.             }  
  52.         });  
  53. new
  54. public void
  55. "";  
  56. for
  57. " ";  
  58. new AlertDialog.Builder(MainActivity.this).setTitle("这是你选择的")  
  59.                         .setMessage(finishedPoem).show();  
  60.             }  
  61.         });  
  62.     }  
  63.   
  64. private
  65. 150, 150, Bitmap.Config.RGB_565);  
  66. new
  67. new
  68.   
  69. 128), random.nextInt(128),  
  70. 128)));  
  71. 24);  
  72.         paint.setFlags(Paint.ANTI_ALIAS_FLAG);  
  73. new Rect(0, 0, 150, 150), paint);  
  74.         paint.setColor(Color.WHITE);  
  75.         paint.setTextAlign(Paint.Align.CENTER);  
  76. 75, 75, paint);  
  77.   
  78. return
  79.     }  
  80. }