Android之ViewGroup实现可拖动的GridView

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

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

  


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

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

[java]  view plain copy
  1. /** 
  2.  * 另外一种方式实现动画可拖动item的GridView 
  3.  *  
  4.  * @author way 
  5.  *  
  6.  */  
  7. public class DragGridView extends ViewGroup implements View.OnTouchListener,  
  8.         View.OnClickListener, View.OnLongClickListener {  
  9.     // layout vars  
  10.     public static float childRatio = .9f;  
  11.     protected int colCount, childSize, padding, dpi, scroll = 0;  
  12.     protected float lastDelta = 0;  
  13.     protected Handler handler = new Handler();  
  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 ArrayList<Integer>();  
  20.     // listeners  
  21.     protected OnRearrangeListener onRearrangeListener;  
  22.     protected OnClickListener secondaryOnClickListener;  
  23.     private OnItemClickListener onItemClickListener;  
  24.   
  25.     /** 
  26.      * 拖动item的接口 
  27.      */  
  28.     public interface OnRearrangeListener {  
  29.   
  30.         public abstract void onRearrange(int oldIndex, int newIndex);  
  31.     }  
  32.   
  33.     // CONSTRUCTOR AND HELPERS  
  34.     public DragGridView(Context context, AttributeSet attrs) {  
  35.         super(context, attrs);  
  36.         setListeners();  
  37.         handler.removeCallbacks(updateTask);  
  38.         handler.postAtTime(updateTask, SystemClock.uptimeMillis() + 500);  
  39.         setChildrenDrawingOrderEnabled(true);  
  40.   
  41.         DisplayMetrics metrics = new DisplayMetrics();  
  42.         ((Activity) context).getWindowManager().getDefaultDisplay()  
  43.                 .getMetrics(metrics);  
  44.         dpi = metrics.densityDpi;  
  45.     }  
  46.   
  47.     protected void setListeners() {  
  48.         setOnTouchListener(this);  
  49.         super.setOnClickListener(this);  
  50.         setOnLongClickListener(this);  
  51.     }  
  52.   
  53.     @Override  
  54.     public void setOnClickListener(OnClickListener l) {  
  55.         secondaryOnClickListener = l;  
  56.     }  
  57.   
  58.     protected Runnable updateTask = new Runnable() {  
  59.         public void run() {  
  60.             if (dragged != -1) {  
  61.                 if (lastY < padding * 3 && scroll > 0)  
  62.                     scroll -= 20;  
  63.                 else if (lastY > getBottom() - getTop() - (padding * 3)  
  64.                         && scroll < getMaxScroll())  
  65.                     scroll += 20;  
  66.             } else if (lastDelta != 0 && !touching) {  
  67.                 scroll += lastDelta;  
  68.                 lastDelta *= .9;  
  69.                 if (Math.abs(lastDelta) < .25)  
  70.                     lastDelta = 0;  
  71.             }  
  72.             clampScroll();  
  73.             onLayout(true, getLeft(), getTop(), getRight(), getBottom());  
  74.   
  75.             handler.postDelayed(this25);  
  76.         }  
  77.     };  
  78.   
  79.     @Override  
  80.     public void addView(View child) {  
  81.         super.addView(child);  
  82.         newPositions.add(-1);  
  83.     };  
  84.   
  85.     @Override  
  86.     public void removeViewAt(int index) {  
  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 b) {  
  94.         // compute width of view, in dp  
  95.         float w = (r - l) / (dpi / 160f);  
  96.   
  97.         // determine number of columns, at least 2  
  98.         colCount = 2;  
  99.         int sub = 240;  
  100.         w -= 280;  
  101.         while (w > 0) {  
  102.             colCount++;  
  103.             w -= sub;  
  104.             sub += 40;  
  105.         }  
  106.   
  107.         // determine childSize and padding, in px  
  108.         childSize = (r - l) / colCount;  
  109.         childSize = Math.round(childSize * childRatio);  
  110.         padding = ((r - l) - (childSize * colCount)) / (colCount + 1);  
  111.   
  112.         for (int i = 0; i < getChildCount(); i++)  
  113.             if (i != dragged) {  
  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 i) {  
  122.         if (dragged == -1)  
  123.             return i;  
  124.         else if (i == childCount - 1)  
  125.             return dragged;  
  126.         else if (i >= dragged)  
  127.             return i + 1;  
  128.         return i;  
  129.     }  
  130.   
  131.     public int getIndexFromCoor(int x, int y) {  
  132.         int col = getColOrRowFromCoor(x), row = getColOrRowFromCoor(y + scroll);  
  133.         if (col == -1 || row == -1// touch is between columns or rows  
  134.             return -1;  
  135.         int index = row * colCount + col;  
  136.         if (index >= getChildCount())  
  137.             return -1;  
  138.         return index;  
  139.     }  
  140.   
  141.     protected int getColOrRowFromCoor(int coor) {  
  142.         coor -= padding;  
  143.         for (int i = 0; coor > 0; i++) {  
  144.             if (coor < childSize)  
  145.                 return i;  
  146.             coor -= (childSize + padding);  
  147.         }  
  148.         return -1;  
  149.     }  
  150.   
  151.     protected int getTargetFromCoor(int x, int y) {  
  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.             target = leftPos + 1;  
  170.         if (dragged < target)  
  171.             return target - 1;  
  172.   
  173.         // Toast.makeText(getContext(), "Target: " + target + ".",  
  174.         // Toast.LENGTH_SHORT).show();  
  175.         return target;  
  176.     }  
  177.   
  178.     protected Point getCoorFromIndex(int index) {  
  179.         int col = index % colCount;  
  180.         int row = index / colCount;  
  181.         return new Point(padding + (childSize + padding) * col, padding  
  182.                 + (childSize + padding) * row - scroll);  
  183.     }  
  184.   
  185.     public int getIndexOf(View child) {  
  186.         for (int i = 0; i < getChildCount(); i++)  
  187.             if (getChildAt(i) == child)  
  188.                 return i;  
  189.         return -1;  
  190.     }  
  191.   
  192.     // EVENT HANDLERS  
  193.     public void onClick(View view) {  
  194.         if (enabled) {  
  195.             if (secondaryOnClickListener != null)  
  196.                 secondaryOnClickListener.onClick(view);  
  197.             if (onItemClickListener != null && getLastIndex() != -1)  
  198.                 onItemClickListener.onItemClick(null,  
  199.                         getChildAt(getLastIndex()), getLastIndex(),  
  200.                         getLastIndex() / colCount);  
  201.         }  
  202.     }  
  203.   
  204.     public boolean onLongClick(View view) {  
  205.         if (!enabled)  
  206.             return false;  
  207.         int index = getLastIndex();  
  208.         if (index != -1) {  
  209.             dragged = index;  
  210.             animateDragged();  
  211.             return true;  
  212.         }  
  213.         return false;  
  214.     }  
  215.   
  216.     public boolean onTouch(View view, MotionEvent event) {  
  217.         int action = event.getAction();  
  218.         switch (action & MotionEvent.ACTION_MASK) {  
  219.         case MotionEvent.ACTION_DOWN:  
  220.             enabled = true;  
  221.             lastX = (int) event.getX();  
  222.             lastY = (int) event.getY();  
  223.             touching = true;  
  224.             break;  
  225.         case MotionEvent.ACTION_MOVE:  
  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.                 getChildAt(dragged).layout(l, t, l + (childSize * 3 / 2),  
  232.                         t + (childSize * 3 / 2));  
  233.   
  234.                 // check for new target hover  
  235.                 int target = getTargetFromCoor(x, y);  
  236.                 if (lastTarget != target) {  
  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.                     enabled = false;  
  247.                 onLayout(true, getLeft(), getTop(), getRight(), getBottom());  
  248.             }  
  249.             lastX = (int) event.getX();  
  250.             lastY = (int) event.getY();  
  251.             lastDelta = delta;  
  252.             break;  
  253.         case MotionEvent.ACTION_UP:  
  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 ImageView)  
  264.                     ((ImageView) v).setAlpha(255);  
  265.                 lastTarget = -1;  
  266.                 dragged = -1;  
  267.             }  
  268.             touching = false;  
  269.             break;  
  270.         }  
  271.         if (dragged != -1)  
  272.             return true;  
  273.         return false;  
  274.     }  
  275.   
  276.     // EVENT HELPERS  
  277.     protected void animateDragged() {  
  278.         View v = getChildAt(dragged);  
  279.         int x = getCoorFromIndex(dragged).x + childSize / 2, y = getCoorFromIndex(dragged).y  
  280.                 + childSize / 2;  
  281.         int l = x - (3 * childSize / 4), t = y - (3 * childSize / 4);  
  282.         v.layout(l, t, l + (childSize * 3 / 2), t + (childSize * 3 / 2));  
  283.         AnimationSet animSet = new AnimationSet(true);  
  284.         ScaleAnimation scale = new ScaleAnimation(.667f, 1, .667f, 1,  
  285.                 childSize * 3 / 4, childSize * 3 / 4);  
  286.         scale.setDuration(animT);  
  287.         AlphaAnimation alpha = new AlphaAnimation(1, .5f);  
  288.         alpha.setDuration(animT);  
  289.   
  290.         animSet.addAnimation(scale);  
  291.         animSet.addAnimation(alpha);  
  292.         animSet.setFillEnabled(true);  
  293.         animSet.setFillAfter(true);  
  294.   
  295.         v.clearAnimation();  
  296.         v.startAnimation(animSet);  
  297.     }  
  298.   
  299.     protected void animateGap(int target) {  
  300.         for (int i = 0; i < getChildCount(); i++) {  
  301.             View v = getChildAt(i);  
  302.             if (i == dragged)  
  303.                 continue;  
  304.             int newPos = i;  
  305.             if (dragged < target && i >= dragged + 1 && i <= target)  
  306.                 newPos--;  
  307.             else if (target < dragged && i >= target && i < dragged)  
  308.                 newPos++;  
  309.   
  310.             // animate  
  311.             int oldPos = i;  
  312.             if (newPositions.get(i) != -1)  
  313.                 oldPos = newPositions.get(i);  
  314.             if (oldPos == newPos)  
  315.                 continue;  
  316.   
  317.             Point oldXY = getCoorFromIndex(oldPos);  
  318.             Point newXY = getCoorFromIndex(newPos);  
  319.             Point oldOffset = new Point(oldXY.x - v.getLeft(), oldXY.y  
  320.                     - v.getTop());  
  321.             Point newOffset = new Point(newXY.x - v.getLeft(), newXY.y  
  322.                     - v.getTop());  
  323.   
  324.             TranslateAnimation translate = new TranslateAnimation(  
  325.                     Animation.ABSOLUTE, oldOffset.x, Animation.ABSOLUTE,  
  326.                     newOffset.x, Animation.ABSOLUTE, oldOffset.y,  
  327.                     Animation.ABSOLUTE, newOffset.y);  
  328.             translate.setDuration(animT);  
  329.             translate.setFillEnabled(true);  
  330.             translate.setFillAfter(true);  
  331.             v.clearAnimation();  
  332.             v.startAnimation(translate);  
  333.   
  334.             newPositions.set(i, newPos);  
  335.         }  
  336.     }  
  337.   
  338.     protected void reorderChildren() {  
  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.         ArrayList<View> children = new ArrayList<View>();  
  344.         for (int i = 0; i < getChildCount(); i++) {  
  345.             getChildAt(i).clearAnimation();  
  346.             children.add(getChildAt(i));  
  347.         }  
  348.         removeAllViews();  
  349.         while (dragged != lastTarget)  
  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.                 Collections.swap(children, dragged, dragged + 1);  
  358.                 dragged++;  
  359.             } else if (dragged > lastTarget) // shift to the left  
  360.             {  
  361.                 Collections.swap(children, dragged, dragged - 1);  
  362.                 dragged--;  
  363.             }  
  364.         for (int i = 0; i < children.size(); i++) {  
  365.             newPositions.set(i, -1);  
  366.             addView(children.get(i));  
  367.         }  
  368.         onLayout(true, getLeft(), getTop(), getRight(), getBottom());  
  369.     }  
  370.   
  371.     public void scrollToTop() {  
  372.         scroll = 0;  
  373.     }  
  374.   
  375.     public void scrollToBottom() {  
  376.         scroll = Integer.MAX_VALUE;  
  377.         clampScroll();  
  378.     }  
  379.   
  380.     protected void clampScroll() {  
  381.         int stretch = 3, overreach = getHeight() / 2;  
  382.         int max = getMaxScroll();  
  383.         max = Math.max(max, 0);  
  384.   
  385.         if (scroll < -overreach) {  
  386.             scroll = -overreach;  
  387.             lastDelta = 0;  
  388.         } else if (scroll > max + overreach) {  
  389.             scroll = max + overreach;  
  390.             lastDelta = 0;  
  391.         } else if (scroll < 0) {  
  392.             if (scroll >= -stretch)  
  393.                 scroll = 0;  
  394.             else if (!touching)  
  395.                 scroll -= scroll / stretch;  
  396.         } else if (scroll > max) {  
  397.             if (scroll <= max + stretch)  
  398.                 scroll = max;  
  399.             else if (!touching)  
  400.                 scroll += (max - scroll) / stretch;  
  401.         }  
  402.     }  
  403.   
  404.     protected int getMaxScroll() {  
  405.         int rowCount = (int) Math.ceil((double) getChildCount() / colCount), max = rowCount  
  406.                 * childSize + (rowCount + 1) * padding - getHeight();  
  407.         return max;  
  408.     }  
  409.   
  410.     public int getLastIndex() {  
  411.         return getIndexFromCoor(lastX, lastY);  
  412.     }  
  413.   
  414.     // OTHER METHODS  
  415.     public void setOnRearrangeListener(OnRearrangeListener l) {  
  416.         this.onRearrangeListener = l;  
  417.     }  
  418.   
  419.     public void setOnItemClickListener(OnItemClickListener l) {  
  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 Activity {  
  8.     static Random random = new Random();  
  9.     static String[] words = "我 是 一 只 大 笨 猪".split(" ");  
  10.     DragGridView mDragGridView;  
  11.     Button mAddBtn, mViewBtn;  
  12.     ArrayList<String> poem = new ArrayList<String>();  
  13.   
  14.     @Override  
  15.     public void onCreate(Bundle savedInstanceState) {  
  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 setListeners() {  
  27.         mDragGridView.setOnRearrangeListener(new OnRearrangeListener() {  
  28.             public void onRearrange(int oldIndex, int newIndex) {  
  29.                 String word = poem.remove(oldIndex);  
  30.                 if (oldIndex < newIndex)  
  31.                     poem.add(newIndex, word);  
  32.                 else  
  33.                     poem.add(newIndex, word);  
  34.             }  
  35.         });  
  36.         mDragGridView.setOnItemClickListener(new OnItemClickListener() {  
  37.             @Override  
  38.             public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,  
  39.                     long arg3) {  
  40.                 mDragGridView.removeViewAt(arg2);  
  41.                 poem.remove(arg2);  
  42.             }  
  43.         });  
  44.         mAddBtn.setOnClickListener(new OnClickListener() {  
  45.             public void onClick(View arg0) {  
  46.                 String word = words[random.nextInt(words.length)];  
  47.                 ImageView view = new ImageView(MainActivity.this);  
  48.                 view.setImageBitmap(getThumb(word));  
  49.                 mDragGridView.addView(view);  
  50.                 poem.add(word);  
  51.             }  
  52.         });  
  53.         mViewBtn.setOnClickListener(new OnClickListener() {  
  54.             public void onClick(View arg0) {  
  55.                 String finishedPoem = "";  
  56.                 for (String s : poem)  
  57.                     finishedPoem += s + " ";  
  58.                 new AlertDialog.Builder(MainActivity.this).setTitle("这是你选择的")  
  59.                         .setMessage(finishedPoem).show();  
  60.             }  
  61.         });  
  62.     }  
  63.   
  64.     private Bitmap getThumb(String s) {  
  65.         Bitmap bmp = Bitmap.createBitmap(150150, Bitmap.Config.RGB_565);  
  66.         Canvas canvas = new Canvas(bmp);  
  67.         Paint paint = new Paint();  
  68.   
  69.         paint.setColor(Color.rgb(random.nextInt(128), random.nextInt(128),  
  70.                 random.nextInt(128)));  
  71.         paint.setTextSize(24);  
  72.         paint.setFlags(Paint.ANTI_ALIAS_FLAG);  
  73.         canvas.drawRect(new Rect(00150150), paint);  
  74.         paint.setColor(Color.WHITE);  
  75.         paint.setTextAlign(Paint.Align.CENTER);  
  76.         canvas.drawText(s, 7575, paint);  
  77.   
  78.         return bmp;  
  79.     }  
  80. }  

很简单的几段代码,相信不用我说,大家都能看明白,最后,附上源码:

http://download.csdn.net/detail/weidi1989/6457871

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值