关闭

Android ListView的子项的随意拖动效果

638人阅读 评论(0) 收藏 举报
分类:

自定义ListView:

[java] view plain copy
  1. package com.miao.listview;  
  2.   
  3. import android.content.Context;  
  4. import android.content.res.TypedArray;  
  5. import android.graphics.Bitmap;  
  6. import android.graphics.PixelFormat;  
  7. import android.graphics.Rect;  
  8. import android.util.AttributeSet;  
  9. import android.view.GestureDetector;  
  10. import android.view.Gravity;  
  11. import android.view.MotionEvent;  
  12. import android.view.View;  
  13. import android.view.ViewConfiguration;  
  14. import android.view.ViewGroup;  
  15. import android.view.WindowManager;  
  16. import android.view.GestureDetector.SimpleOnGestureListener;  
  17. import android.widget.AdapterView;  
  18. import android.widget.ImageView;  
  19. import android.widget.ListView;  
  20. import com.miao.listview.R;  
  21.   
  22. public class DraggableListView extends ListView {  
  23.     private ImageView mDragView;  
  24.     private WindowManager mWindowManager;  
  25.     private WindowManager.LayoutParams mWindowParams;  
  26.     private int mDragPos; // which item is being dragged  
  27.     private int mFirstDragPos; // where was the dragged item originally  
  28.     private int mDragPoint; // at what offset inside the item did the user grab  
  29.                             // it  
  30.     private int mCoordOffset; // the difference between screen coordinates and  
  31.                                 // coordinates in this view  
  32.     private DragListener mDragListener;  
  33.     private DropListener mDropListener;  
  34.     private RemoveListener mRemoveListener;  
  35.     private int mUpperBound;  
  36.     private int mLowerBound;  
  37.     private int mHeight;  
  38.     private GestureDetector mGestureDetector;  
  39.     public static final int FLING = 0;  
  40.     public static final int SLIDE_RIGHT = 1;  
  41.     public static final int SLIDE_LEFT = 2;  
  42.     private int mRemoveMode = -1;  
  43.     private Rect mTempRect = new Rect();  
  44.     private Bitmap mDragBitmap;  
  45.     private final int mTouchSlop;  
  46.     private int mItemHeightNormal = -1;  
  47.     private int mItemHeightExpanded = -1;  
  48.     private int grabberId = -1;  
  49.     private int dragndropBackgroundColor = 0x00000000;  
  50.   
  51.     public DraggableListView(Context context, AttributeSet attrs) {  
  52.         this(context, attrs, 0);  
  53.     }  
  54.   
  55.     public DraggableListView(Context context, AttributeSet attrs, int defStyle) {  
  56.         super(context, attrs, defStyle);  
  57.   
  58.         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  
  59.   
  60.         if (attrs != null) {  
  61.             TypedArray a = getContext().obtainStyledAttributes(attrs,  
  62.                     R.styleable.TouchListView, 00);  
  63.   
  64.             mItemHeightNormal = a.getDimensionPixelSize(  
  65.                     R.styleable.TouchListView_normal_height, 0);  
  66.             mItemHeightExpanded = a.getDimensionPixelSize(  
  67.                     R.styleable.TouchListView_expanded_height,  
  68.                     mItemHeightNormal);  
  69.             grabberId = a.getResourceId(R.styleable.TouchListView_grabber, -1);  
  70.             dragndropBackgroundColor = a.getColor(  
  71.                     R.styleable.TouchListView_dragndrop_background, 0x00000000);  
  72.             mRemoveMode = a.getInt(R.styleable.TouchListView_remove_mode, -1);  
  73.   
  74.             a.recycle();  
  75.         }  
  76.     }  
  77.   
  78.     @Override  
  79.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  80.         if (mRemoveListener != null && mGestureDetector == null) {  
  81.             if (mRemoveMode == FLING) {  
  82.                 mGestureDetector = new GestureDetector(getContext(),  
  83.                         new SimpleOnGestureListener() {  
  84.                             @Override  
  85.                             public boolean onFling(MotionEvent e1,  
  86.                                     MotionEvent e2, float velocityX,  
  87.                                     float velocityY) {  
  88.                                 if (mDragView != null) {  
  89.                                     if (velocityX > 1000) {  
  90.                                         Rect r = mTempRect;  
  91.                                         mDragView.getDrawingRect(r);  
  92.                                         if (e2.getX() > r.right * 2 / 3) {  
  93.                                             // fast fling right with release  
  94.                                             // near the right edge of the screen  
  95.                                             stopDragging();  
  96.                                             mRemoveListener  
  97.                                                     .remove(mFirstDragPos);  
  98.                                             unExpandViews(true);  
  99.                                         }  
  100.                                     }  
  101.                                     // flinging while dragging should have no  
  102.                                     // effect  
  103.                                     return true;  
  104.                                 }  
  105.                                 return false;  
  106.                             }  
  107.                         });  
  108.             }  
  109.         }  
  110.         if (mDragListener != null || mDropListener != null) {  
  111.             switch (ev.getAction()) {  
  112.             case MotionEvent.ACTION_DOWN:  
  113.                 int x = (int) ev.getX();  
  114.                 int y = (int) ev.getY();  
  115.                 int itemnum = pointToPosition(x, y);  
  116.                 if (itemnum == AdapterView.INVALID_POSITION) {  
  117.                     break;  
  118.                 }  
  119.                 ViewGroup item = (ViewGroup) getChildAt(itemnum  
  120.                         - getFirstVisiblePosition());  
  121.                 mDragPoint = y - item.getTop();  
  122.                 mCoordOffset = ((int) ev.getRawY()) - y;  
  123.                 View dragger = item.findViewById(grabberId);  
  124.                 Rect r = mTempRect;  
  125.                 // dragger.getDrawingRect(r);  
  126.   
  127.                 r.left = dragger.getLeft();  
  128.                 r.right = dragger.getRight();  
  129.                 r.top = dragger.getTop();  
  130.                 r.bottom = dragger.getBottom();  
  131.   
  132.                 if ((r.left < x) && (x < r.right)) {  
  133.                     item.setDrawingCacheEnabled(true);  
  134.                     // Create a copy of the drawing cache so that it does not  
  135.                     // get recycled  
  136.                     // by the framework when the list tries to clean up memory  
  137.                     Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());  
  138.                     startDragging(bitmap, y);  
  139.                     mDragPos = itemnum;  
  140.                     mFirstDragPos = mDragPos;  
  141.                     mHeight = getHeight();  
  142.                     int touchSlop = mTouchSlop;  
  143.                     mUpperBound = Math.min(y - touchSlop, mHeight / 3);  
  144.                     mLowerBound = Math.max(y + touchSlop, mHeight * 2 / 3);  
  145.                     return false;  
  146.                 }  
  147.                 mDragView = null;  
  148.                 break;  
  149.             }  
  150.         }  
  151.         return super.onInterceptTouchEvent(ev);  
  152.     }  
  153.   
  154.     /* 
  155.      * pointToPosition() doesn't consider invisible views, but we need to, so 
  156.      * implement a slightly different version. 
  157.      */  
  158.     private int myPointToPosition(int x, int y) {  
  159.         Rect frame = mTempRect;  
  160.         final int count = getChildCount();  
  161.         for (int i = count - 1; i >= 0; i--) {  
  162.             final View child = getChildAt(i);  
  163.             child.getHitRect(frame);  
  164.             if (frame.contains(x, y)) {  
  165.                 return getFirstVisiblePosition() + i;  
  166.             }  
  167.         }  
  168.         return INVALID_POSITION;  
  169.     }  
  170.   
  171.     private int getItemForPosition(int y) {  
  172.         int adjustedy = y - mDragPoint - 32;  
  173.         int pos = myPointToPosition(0, adjustedy);  
  174.         if (pos >= 0) {  
  175.             if (pos <= mFirstDragPos) {  
  176.                 pos += 1;  
  177.             }  
  178.         } else if (adjustedy < 0) {  
  179.             pos = 0;  
  180.         }  
  181.         return pos;  
  182.     }  
  183.   
  184.     private void adjustScrollBounds(int y) {  
  185.         if (y >= mHeight / 3) {  
  186.             mUpperBound = mHeight / 3;  
  187.         }  
  188.         if (y <= mHeight * 2 / 3) {  
  189.             mLowerBound = mHeight * 2 / 3;  
  190.         }  
  191.     }  
  192.   
  193.     /* 
  194.      * Restore size and visibility for all listitems 
  195.      */  
  196.     private void unExpandViews(boolean deletion) {  
  197.         for (int i = 0;; i++) {  
  198.             View v = getChildAt(i);  
  199.             if (v == null) {  
  200.                 if (deletion) {  
  201.                     // HACK force update of mItemCount  
  202.                     int position = getFirstVisiblePosition();  
  203.                     int y = getChildAt(0).getTop();  
  204.                     setAdapter(getAdapter());  
  205.                     setSelectionFromTop(position, y);  
  206.                     // end hack  
  207.                 }  
  208.                 layoutChildren(); // force children to be recreated where needed  
  209.                 v = getChildAt(i);  
  210.                 if (v == null) {  
  211.                     break;  
  212.                 }  
  213.             }  
  214.             ViewGroup.LayoutParams params = v.getLayoutParams();  
  215.             params.height = mItemHeightNormal;  
  216.             v.setLayoutParams(params);  
  217.             v.setVisibility(View.VISIBLE);  
  218.         }  
  219.     }  
  220.   
  221.     /* 
  222.      * Adjust visibility and size to make it appear as though an item is being 
  223.      * dragged around and other items are making room for it: If dropping the 
  224.      * item would result in it still being in the same place, then make the 
  225.      * dragged listitem's size normal, but make the item invisible. Otherwise, 
  226.      * if the dragged listitem is still on screen, make it as small as possible 
  227.      * and expand the item below the insert point. If the dragged item is not on 
  228.      * screen, only expand the item below the current insertpoint. 
  229.      */  
  230.     private void doExpansion() {  
  231.         int childnum = mDragPos - getFirstVisiblePosition();  
  232.         if (mDragPos > mFirstDragPos) {  
  233.             childnum++;  
  234.         }  
  235.   
  236.         View first = getChildAt(mFirstDragPos - getFirstVisiblePosition());  
  237.   
  238.         for (int i = 0;; i++) {  
  239.             View vv = getChildAt(i);  
  240.             if (vv == null) {  
  241.                 break;  
  242.             }  
  243.             int height = mItemHeightNormal;  
  244.             int visibility = View.VISIBLE;  
  245.             if (vv.equals(first)) {  
  246.                 // processing the item that is being dragged  
  247.                 if (mDragPos == mFirstDragPos) {  
  248.                     // hovering over the original location  
  249.                     visibility = View.INVISIBLE;  
  250.                 } else {  
  251.                     // not hovering over it  
  252.                     height = 1;  
  253.                 }  
  254.             } else if (i == childnum) {  
  255.                 if (mDragPos < getCount() - 1) {  
  256.                     height = mItemHeightExpanded;  
  257.                 }  
  258.             }  
  259.             ViewGroup.LayoutParams params = vv.getLayoutParams();  
  260.             params.height = height;  
  261.             vv.setLayoutParams(params);  
  262.             vv.setVisibility(visibility);  
  263.         }  
  264.     }  
  265.   
  266.     @Override  
  267.     public boolean onTouchEvent(MotionEvent ev) {  
  268.         if (mGestureDetector != null) {  
  269.             mGestureDetector.onTouchEvent(ev);  
  270.         }  
  271.         if ((mDragListener != null || mDropListener != null)  
  272.                 && mDragView != null) {  
  273.             int action = ev.getAction();  
  274.             switch (action) {  
  275.             case MotionEvent.ACTION_UP:  
  276.             case MotionEvent.ACTION_CANCEL:  
  277.                 Rect r = mTempRect;  
  278.                 mDragView.getDrawingRect(r);  
  279.                 stopDragging();  
  280.                 if (mDropListener != null && mDragPos >= 0  
  281.                         && mDragPos < getCount()) {  
  282.                     mDropListener.drop(mFirstDragPos, mDragPos);  
  283.                 }  
  284.                 unExpandViews(false);  
  285.                 break;  
  286.   
  287.             case MotionEvent.ACTION_DOWN:  
  288.             case MotionEvent.ACTION_MOVE:  
  289.                 int x = (int) ev.getX();  
  290.                 int y = (int) ev.getY();  
  291.                 dragView(x, y);  
  292.                 int itemnum = getItemForPosition(y);  
  293.                 if (itemnum >= 0) {  
  294.                     if (action == MotionEvent.ACTION_DOWN  
  295.                             || itemnum != mDragPos) {  
  296.                         if (mDragListener != null) {  
  297.                             mDragListener.drag(mDragPos, itemnum);  
  298.                         }  
  299.                         mDragPos = itemnum;  
  300.                         doExpansion();  
  301.                     }  
  302.                     int speed = 0;  
  303.                     adjustScrollBounds(y);  
  304.                     if (y > mLowerBound) {  
  305.                         // scroll the list up a bit  
  306.                         speed = y > (mHeight + mLowerBound) / 2 ? 16 : 4;  
  307.                     } else if (y < mUpperBound) {  
  308.                         // scroll the list down a bit  
  309.                         speed = y < mUpperBound / 2 ? -16 : -4;  
  310.                     }  
  311.                     if (speed != 0) {  
  312.                         int ref = pointToPosition(0, mHeight / 2);  
  313.                         if (ref == AdapterView.INVALID_POSITION) {  
  314.                             // we hit a divider or an invisible view, check  
  315.                             // somewhere else  
  316.                             ref = pointToPosition(0, mHeight / 2  
  317.                                     + getDividerHeight() + 64);  
  318.                         }  
  319.                         View v = getChildAt(ref - getFirstVisiblePosition());  
  320.                         if (v != null) {  
  321.                             int pos = v.getTop();  
  322.                             setSelectionFromTop(ref, pos - speed);  
  323.                         }  
  324.                     }  
  325.                 }  
  326.                 break;  
  327.             }  
  328.             return true;  
  329.         }  
  330.         return super.onTouchEvent(ev);  
  331.     }  
  332.   
  333.     private void startDragging(Bitmap bm, int y) {  
  334.         stopDragging();  
  335.   
  336.         mWindowParams = new WindowManager.LayoutParams();  
  337.         mWindowParams.gravity = Gravity.TOP;  
  338.         mWindowParams.x = 0;  
  339.         mWindowParams.y = y - mDragPoint + mCoordOffset;  
  340.   
  341.         mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;  
  342.         mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;  
  343.         mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE  
  344.                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE  
  345.                 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON  
  346.                 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;  
  347.         mWindowParams.format = PixelFormat.TRANSLUCENT;  
  348.         mWindowParams.windowAnimations = 0;  
  349.   
  350.         ImageView v = new ImageView(getContext());  
  351.         // int backGroundColor =  
  352.         // getContext().getResources().getColor(R.color.dragndrop_background);  
  353.         v.setBackgroundColor(dragndropBackgroundColor);  
  354.         v.setImageBitmap(bm);  
  355.         mDragBitmap = bm;  
  356.   
  357.         mWindowManager = (WindowManager) getContext()  
  358.                 .getSystemService("window");  
  359.         mWindowManager.addView(v, mWindowParams);  
  360.         mDragView = v;  
  361.     }  
  362.   
  363.     private void dragView(int x, int y) {  
  364.         float alpha = 1.0f;  
  365.         int width = mDragView.getWidth();  
  366.   
  367.         if (mRemoveMode == SLIDE_RIGHT) {  
  368.             if (x > width / 2) {  
  369.                 alpha = ((float) (width - x)) / (width / 2);  
  370.             }  
  371.             mWindowParams.alpha = alpha;  
  372.         } else if (mRemoveMode == SLIDE_LEFT) {  
  373.             if (x < width / 2) {  
  374.                 alpha = ((float) x) / (width / 2);  
  375.             }  
  376.             mWindowParams.alpha = alpha;  
  377.         }  
  378.         mWindowParams.y = y - mDragPoint + mCoordOffset;  
  379.         mWindowManager.updateViewLayout(mDragView, mWindowParams);  
  380.     }  
  381.   
  382.     private void stopDragging() {  
  383.         if (mDragView != null) {  
  384.             WindowManager wm = (WindowManager) getContext().getSystemService(  
  385.                     "window");  
  386.             wm.removeView(mDragView);  
  387.             mDragView.setImageDrawable(null);  
  388.             mDragView = null;  
  389.         }  
  390.         if (mDragBitmap != null) {  
  391.             mDragBitmap.recycle();  
  392.             mDragBitmap = null;  
  393.         }  
  394.     }  
  395.   
  396.     public void setDragListener(DragListener l) {  
  397.         mDragListener = l;  
  398.     }  
  399.   
  400.     public void setDropListener(DropListener l) {  
  401.         mDropListener = l;  
  402.     }  
  403.   
  404.     public void setRemoveListener(RemoveListener l) {  
  405.         mRemoveListener = l;  
  406.     }  
  407.   
  408.     public interface DragListener {  
  409.         void drag(int from, int to);  
  410.     }  
  411.   
  412.     public interface DropListener {  
  413.         void drop(int from, int to);  
  414.     }  
  415.   
  416.     public interface RemoveListener {  
  417.         void remove(int which);  
  418.     }  
  419. }  
调用自定义view:

[java] view plain copy
  1. package com.miao.listview;  
  2.   
  3. import android.os.Bundle;  
  4. import android.app.ListActivity;  
  5. import android.view.LayoutInflater;  
  6. import android.view.View;  
  7. import android.view.ViewGroup;  
  8. import android.widget.ArrayAdapter;  
  9. import android.widget.TextView;  
  10. import android.widget.Toast;  
  11. import com.miao.listview.R;  
  12.   
  13. import java.util.ArrayList;  
  14. import java.util.Arrays;  
  15.   
  16. public class DragDemo extends ListActivity {  
  17.     private static String[] items = { "浙江""江苏""广东""上海""北京""新疆" };  
  18.     private IconicAdapter adapter = null;  
  19.     private ArrayList<String> array = new ArrayList<String>(  
  20.             Arrays.asList(items));  
  21.   
  22.     @Override  
  23.     public void onCreate(Bundle icicle) {  
  24.         super.onCreate(icicle);  
  25.         setContentView(R.layout.main);  
  26.   
  27.         adapter = new IconicAdapter();  
  28.         setListAdapter(adapter);  
  29.   
  30.         DraggableListView tlv = (DraggableListView) getListView();  
  31.   
  32.         tlv.setDropListener(onDrop);  
  33.         tlv.setRemoveListener(onRemove);  
  34.         tlv.getAdapter();  
  35.     }  
  36.   
  37.     private DraggableListView.DropListener onDrop = new DraggableListView.DropListener() {  
  38.         @Override  
  39.         public void drop(int from, int to) {  
  40.             String item = adapter.getItem(from);  
  41.   
  42.             adapter.remove(item);  
  43.             adapter.insert(item, to);  
  44.             Toast.makeText(DragDemo.this, adapter.getList().toString(),  
  45.                     Toast.LENGTH_SHORT).show();  
  46.         }  
  47.     };  
  48.   
  49.     private DraggableListView.RemoveListener onRemove = new DraggableListView.RemoveListener() {  
  50.         @Override  
  51.         public void remove(int which) {  
  52.             adapter.remove(adapter.getItem(which));  
  53.         }  
  54.     };  
  55.   
  56.     class IconicAdapter extends ArrayAdapter<String> {  
  57.         IconicAdapter() {  
  58.             super(DragDemo.this, R.layout.row, array);  
  59.         }  
  60.   
  61.         public ArrayList<String> getList() {  
  62.             return array;  
  63.         }  
  64.   
  65.         public View getView(int position, View convertView, ViewGroup parent) {  
  66.             View row = convertView;  
  67.             if (row == null) {  
  68.                 LayoutInflater inflater = getLayoutInflater();  
  69.                 row = inflater.inflate(R.layout.row, parent, false);  
  70.             }  
  71.             TextView label = (TextView) row.findViewById(R.id.label);  
  72.             label.setText(array.get(position));  
  73.             return (row);  
  74.         }  
  75.     }  
  76. }  


main.xml:

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <com.miao.listview.DraggableListView  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     xmlns:tlv="http://schemas.android.com/apk/res/com.miao.listview"  
  5.     android:id="@android:id/list"  
  6.     android:layout_width="fill_parent"  
  7.     android:layout_height="fill_parent"  
  8.     android:drawSelectorOnTop="false"  
  9.     tlv:normal_height="64dip"  
  10.     tlv:grabber="@+id/icon"  
  11.     tlv:remove_mode="slideLeft"  
  12. />  

row.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="64dip"  
  5.     android:gravity="center_vertical"  
  6.     android:ignoreGravity="@+id/icon">  
  7.     <ImageView android:id="@+id/icon"  
  8.         android:layout_alignParentRight="true"  
  9.         android:layout_alignParentTop="true"  
  10.         android:layout_alignParentBottom="true"  
  11.         android:layout_width="wrap_content"  
  12.         android:layout_height="wrap_content"  
  13.                 android:src="@drawable/grabber"  
  14.         />  
  15.         <TextView android:id="@+id/label"  
  16.         android:textAppearance="?android:attr/textAppearanceMedium"  
  17.         android:layout_width="wrap_content"  
  18.         android:paddingLeft="9dip"  
  19.         android:paddingRight="9dip"  
  20.         android:layout_height="wrap_content"  
  21.         android:layout_alignWithParentIfMissing="true"  
  22.                 android:layout_alignParentLeft="true"  
  23.         android:layout_toLeftOf="@id/icon"  
  24.                 android:layout_centerVertical="true"  
  25.         android:ellipsize="marquee"  
  26.         android:singleLine="true"  
  27.         />  
  28. </RelativeLayout>  

素材图片:



效果图:


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:57097次
    • 积分:921
    • 等级:
    • 排名:千里之外
    • 原创:15篇
    • 转载:136篇
    • 译文:0篇
    • 评论:6条
    文章分类
    最新评论