android listview拖拽,拖动item 改变位置

来源:互联网 发布:ios开发语言 java 编辑:程序博客网 时间:2024/05/16 07:34

转自:http://blog.csdn.net/dany1202/article/details/6109160#comments


在packages/apps/Music/src/touchIncepter.java中

该类提供了listview的拖动效果,并提供接口,在程序接口中实现数据的交换即可。


[java] view plaincopy
  1. package com.and.DragListview;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.app.ListActivity;  
  7. import android.content.Context;  
  8. import android.os.Bundle;  
  9. import android.view.LayoutInflater;  
  10. import android.view.View;  
  11. import android.view.ViewGroup;  
  12. import android.widget.BaseAdapter;  
  13. import android.widget.ImageView;  
  14. import android.widget.TextView;  
  15.   
  16. public class DragListview extends ListActivity {     
  17.     MyAdapter adapter;  
  18.     TouchInterceptor list;  
  19.     List<String> arrayText;  
  20.       
  21.     @Override  
  22.     public void onCreate(Bundle savedInstanceState) {  
  23.         super.onCreate(savedInstanceState);  
  24.         setContentView(R.layout.main);  
  25.           
  26.         list = (TouchInterceptor) getListView();//(TouchInterceptor)findViewById(android.R.id.list);  
  27.         getText();  
  28.           
  29.         adapter = new MyAdapter(this);  
  30.         setListAdapter(adapter);  
  31.          
  32.         list.setDropListener(mDropListener);  
  33.      //   list.setRemoveListener(mRemoveListener);        
  34.     }  
  35.     public void getText(){  
  36.         arrayText = new ArrayList<String>();  
  37.         arrayText.add("传奇");  
  38.         arrayText.add("红豆");  
  39.         arrayText.add("流年");  
  40.         arrayText.add("棋子");  
  41.     }  
  42.       
  43.     //交换listview的数据  
  44.     private TouchInterceptor.DropListener mDropListener =  
  45.         new TouchInterceptor.DropListener() {  
  46.         public void drop(int from, int to) {  
  47.             String item = arrayText.get(from);  
  48.             arrayText.remove(item);//.remove(from);  
  49.             arrayText.add(to, item);  
  50.             adapter.notifyDataSetChanged();  
  51.         }  
  52.     };  
  53.       
  54.     private TouchInterceptor.RemoveListener mRemoveListener =  
  55.         new TouchInterceptor.RemoveListener() {  
  56.         public void remove(int which) {            
  57.         }  
  58.     };  
  59.       
  60.     class MyAdapter extends BaseAdapter{  
  61.         private LayoutInflater mInflater;  
  62.         Context mContext;  
  63.         public MyAdapter(Context c){  
  64.             mInflater = LayoutInflater.from(c);  
  65.         }  
  66.         public int getCount() {           
  67.             return arrayText.size();  
  68.         }  
  69.   
  70.         public Object getItem(int arg0) {  
  71.             return arrayText.get(arg0);  
  72.         }  
  73.   
  74.         public long getItemId(int arg0) {  
  75.             return arg0;  
  76.         }  
  77.   
  78.         public View getView(int arg0, View contentView, ViewGroup arg2) {  
  79.             ImageView img;  
  80.             TextView text;  
  81.             if(contentView==null){  
  82.                 contentView = mInflater.inflate(R.layout.list_layout, null);   
  83.                 //contentView = mInflater.inflate(R.layout.list_layout,null);  
  84.             }  
  85.             img = (ImageView)contentView.findViewById(R.id.img);  
  86.             img.setBackgroundResource(R.drawable.icon);  
  87.             text = (TextView)contentView.findViewById(R.id.text);  
  88.             text.setText(arrayText.get(arg0).toString());  
  89.               
  90.             return contentView;  
  91.         }  
  92.           
  93.     }  
  94. }  

源码中的类:

[java] view plaincopy
  1. /* 
  2.  * Copyright (C) 2008 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package com.and.DragListview;  
  18.   
  19. import android.content.Context;  
  20. import android.content.SharedPreferences;  
  21. import android.content.res.Resources;  
  22. import android.graphics.Bitmap;  
  23. import android.graphics.PixelFormat;  
  24. import android.graphics.Rect;  
  25. import android.util.AttributeSet;  
  26. import android.view.GestureDetector;  
  27. import android.view.Gravity;  
  28. import android.view.MotionEvent;  
  29. import android.view.View;  
  30. import android.view.ViewConfiguration;  
  31. import android.view.ViewGroup;  
  32. import android.view.WindowManager;  
  33. import android.view.GestureDetector.SimpleOnGestureListener;  
  34. import android.widget.AdapterView;  
  35. import android.widget.ImageView;  
  36. import android.widget.ListView;  
  37.   
  38. public class TouchInterceptor extends ListView {  
  39.       
  40.     private ImageView mDragView;  
  41.     private WindowManager mWindowManager;  
  42.     private WindowManager.LayoutParams mWindowParams;  
  43.     private int mDragPos;      // which item is being dragged  
  44.     private int mFirstDragPos; // where was the dragged item originally  
  45.     private int mDragPoint;    // at what offset inside the item did the user grab it  
  46.     private int mCoordOffset;  // the difference between screen coordinates and coordinates in this view  
  47.     private DragListener mDragListener;  
  48.     private DropListener mDropListener;  
  49.     private RemoveListener mRemoveListener;  
  50.     private int mUpperBound;  
  51.     private int mLowerBound;  
  52.     private int mHeight;  
  53.     private GestureDetector mGestureDetector;  
  54.     private static final int FLING = 0;  
  55.     private static final int SLIDE = 1;  
  56.     private int mRemoveMode = -1;  
  57.     private Rect mTempRect = new Rect();  
  58.     private Bitmap mDragBitmap;  
  59.     private final int mTouchSlop;  
  60.     private int mItemHeightNormal;  
  61.     private int mItemHeightExpanded;  
  62.     private int mItemHeightHalf;  
  63.   
  64.     public TouchInterceptor(Context context, AttributeSet attrs) {  
  65.         super(context, attrs);  
  66.         SharedPreferences pref = context.getSharedPreferences("Music"3);  
  67.         mRemoveMode = pref.getInt("deletemode", -1);  
  68.         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  
  69.         Resources res = getResources();  
  70.         mItemHeightNormal = 48;//res.getDimensionPixelSize(R.dimen.normal_height);  
  71.         mItemHeightHalf = mItemHeightNormal / 2;  
  72.         mItemHeightExpanded = 96;//res.getDimensionPixelSize(R.dimen.expanded_height);  
  73.     }  
  74.       
  75.     @Override  
  76.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  77.         if (mRemoveListener != null && mGestureDetector == null) {  
  78.             if (mRemoveMode == FLING) {  
  79.                 mGestureDetector = new GestureDetector(getContext(), new SimpleOnGestureListener() {  
  80.                     @Override  
  81.                     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  82.                             float velocityY) {  
  83.                         if (mDragView != null) {  
  84.                             if (velocityX > 1000) {  
  85.                                 Rect r = mTempRect;  
  86.                                 mDragView.getDrawingRect(r);  
  87.                                 if ( e2.getX() > r.right * 2 / 3) {  
  88.                                     // fast fling right with release near the right edge of the screen  
  89.                                     stopDragging();  
  90.                                     mRemoveListener.remove(mFirstDragPos);  
  91.                                     unExpandViews(true);  
  92.                                 }  
  93.                             }  
  94.                             // flinging while dragging should have no effect  
  95.                             return true;  
  96.                         }  
  97.                         return false;  
  98.                     }  
  99.                 });  
  100.             }  
  101.         }  
  102.         if (mDragListener != null || mDropListener != null) {  
  103.             switch (ev.getAction()) {  
  104.                 case MotionEvent.ACTION_DOWN:  
  105.                     int x = (int) ev.getX();  
  106.                     int y = (int) ev.getY();  
  107.                     int itemnum = pointToPosition(x, y);  
  108.                     if (itemnum == AdapterView.INVALID_POSITION) {  
  109.                         break;  
  110.                     }  
  111.                     ViewGroup item = (ViewGroup) getChildAt(itemnum - getFirstVisiblePosition());  
  112.                     mDragPoint = y - item.getTop();  
  113.                     mCoordOffset = ((int)ev.getRawY()) - y;  
  114.                     View dragger = item.findViewById(R.id.img);//..........................  
  115.                     Rect r = mTempRect;  
  116.                     dragger.getDrawingRect(r);  
  117.                     // The dragger icon itself is quite small, so pretend the touch area is bigger  
  118.                     if (x < r.right * 2) {  
  119.                         item.setDrawingCacheEnabled(true);  
  120.                         // Create a copy of the drawing cache so that it does not get recycled  
  121.                         // by the framework when the list tries to clean up memory  
  122.                         Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());  
  123.                         startDragging(bitmap, y);  
  124.                         mDragPos = itemnum;  
  125.                         mFirstDragPos = mDragPos;  
  126.                         mHeight = getHeight();  
  127.                         int touchSlop = mTouchSlop;  
  128.                         mUpperBound = Math.min(y - touchSlop, mHeight / 3);  
  129.                         mLowerBound = Math.max(y + touchSlop, mHeight * 2 /3);  
  130.                         return false;  
  131.                     }  
  132.                     stopDragging();  
  133.                     break;  
  134.             }  
  135.         }  
  136.         return super.onInterceptTouchEvent(ev);  
  137.     }  
  138.       
  139.     /* 
  140.      * pointToPosition() doesn't consider invisible views, but we 
  141.      * need to, so implement a slightly different version. 
  142.      */  
  143.     private int myPointToPosition(int x, int y) {  
  144.   
  145.         if (y < 0) {  
  146.             // when dragging off the top of the screen, calculate position  
  147.             // by going back from a visible item  
  148.             int pos = myPointToPosition(x, y + mItemHeightNormal);  
  149.             if (pos > 0) {  
  150.                 return pos - 1;  
  151.             }  
  152.         }  
  153.   
  154.         Rect frame = mTempRect;  
  155.         final int count = getChildCount();  
  156.         for (int i = count - 1; i >= 0; i--) {  
  157.             final View child = getChildAt(i);  
  158.             child.getHitRect(frame);  
  159.             if (frame.contains(x, y)) {  
  160.                 return getFirstVisiblePosition() + i;  
  161.             }  
  162.         }  
  163.         return INVALID_POSITION;  
  164.     }  
  165.       
  166.     private int getItemForPosition(int y) {  
  167.         int adjustedy = y - mDragPoint - mItemHeightHalf;  
  168.         int pos = myPointToPosition(0, adjustedy);  
  169.         if (pos >= 0) {  
  170.             if (pos <= mFirstDragPos) {  
  171.                 pos += 1;  
  172.             }  
  173.         } else if (adjustedy < 0) {  
  174.             // this shouldn't happen anymore now that myPointToPosition deals  
  175.             // with this situation  
  176.             pos = 0;  
  177.         }  
  178.         return pos;  
  179.     }  
  180.       
  181.     private void adjustScrollBounds(int y) {  
  182.         if (y >= mHeight / 3) {  
  183.             mUpperBound = mHeight / 3;  
  184.         }  
  185.         if (y <= mHeight * 2 / 3) {  
  186.             mLowerBound = mHeight * 2 / 3;  
  187.         }  
  188.     }  
  189.   
  190.     /* 
  191.      * Restore size and visibility for all listitems 
  192.      */  
  193.     private void unExpandViews(boolean deletion) {  
  194.         for (int i = 0;; i++) {  
  195.             View v = getChildAt(i);  
  196.             if (v == null) {  
  197.                 if (deletion) {  
  198.                     // HACK force update of mItemCount  
  199.                     int position = getFirstVisiblePosition();  
  200.                     int y = getChildAt(0).getTop();  
  201.                     setAdapter(getAdapter());  
  202.                     setSelectionFromTop(position, y);  
  203.                     // end hack  
  204.                 }  
  205.                 layoutChildren(); // force children to be recreated where needed  
  206.                 v = getChildAt(i);  
  207.                 if (v == null) {  
  208.                     break;  
  209.                 }  
  210.             }  
  211.             ViewGroup.LayoutParams params = v.getLayoutParams();  
  212.             params.height = mItemHeightNormal;  
  213.             v.setLayoutParams(params);  
  214.             v.setVisibility(View.VISIBLE);  
  215.         }  
  216.     }  
  217.       
  218.     /* Adjust visibility and size to make it appear as though 
  219.      * an item is being dragged around and other items are making 
  220.      * room for it: 
  221.      * If dropping the item would result in it still being in the 
  222.      * same place, then make the dragged listitem's size normal, 
  223.      * but make the item invisible. 
  224.      * Otherwise, if the dragged listitem is still on screen, make 
  225.      * it as small as possible and expand the item below the insert 
  226.      * point. 
  227.      * If the dragged item is not on screen, only expand the item 
  228.      * 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) && mDragView != null) {  
  272.             int action = ev.getAction();   
  273.             switch (action) {  
  274.                 case MotionEvent.ACTION_UP:  
  275.                 case MotionEvent.ACTION_CANCEL:  
  276.                     Rect r = mTempRect;  
  277.                     mDragView.getDrawingRect(r);  
  278.                     stopDragging();  
  279.                     if (mRemoveMode == SLIDE && ev.getX() > r.right * 3 / 4) {  
  280.                         if (mRemoveListener != null) {  
  281.                             mRemoveListener.remove(mFirstDragPos);  
  282.                         }  
  283.                         unExpandViews(true);  
  284.                     } else {  
  285.                         if (mDropListener != null && mDragPos >= 0 && mDragPos < getCount()) {  
  286.                             mDropListener.drop(mFirstDragPos, mDragPos);  
  287.                         }  
  288.                         unExpandViews(false);  
  289.                     }  
  290.                     break;  
  291.                       
  292.                 case MotionEvent.ACTION_DOWN:  
  293.                 case MotionEvent.ACTION_MOVE:  
  294.                     int x = (int) ev.getX();  
  295.                     int y = (int) ev.getY();  
  296.                     dragView(x, y);  
  297.                     int itemnum = getItemForPosition(y);  
  298.                     if (itemnum >= 0) {  
  299.                         if (action == MotionEvent.ACTION_DOWN || itemnum != mDragPos) {  
  300.                             if (mDragListener != null) {  
  301.                                 mDragListener.drag(mDragPos, itemnum);  
  302.                             }  
  303.                             mDragPos = itemnum;  
  304.                             doExpansion();  
  305.                         }  
  306.                         int speed = 0;  
  307.                         adjustScrollBounds(y);  
  308.                         if (y > mLowerBound) {  
  309.                             // scroll the list up a bit  
  310.                             speed = y > (mHeight + mLowerBound) / 2 ? 16 : 4;  
  311.                         } else if (y < mUpperBound) {  
  312.                             // scroll the list down a bit  
  313.                             speed = y < mUpperBound / 2 ? -16 : -4;  
  314.                         }  
  315.                         if (speed != 0) {  
  316.                             int ref = pointToPosition(0, mHeight / 2);  
  317.                             if (ref == AdapterView.INVALID_POSITION) {  
  318.                                 //we hit a divider or an invisible view, check somewhere else  
  319.                                 ref = pointToPosition(0, mHeight / 2 + getDividerHeight() + 64);  
  320.                             }  
  321.                             View v = getChildAt(ref - getFirstVisiblePosition());  
  322.                             if (v!= null) {  
  323.                                 int pos = v.getTop();  
  324.                                 setSelectionFromTop(ref, pos - speed);  
  325.                             }  
  326.                         }  
  327.                     }  
  328.                     break;  
  329.             }  
  330.             return true;  
  331.         }  
  332.         return super.onTouchEvent(ev);  
  333.     }  
  334.       
  335.     private void startDragging(Bitmap bm, int y) {  
  336.         stopDragging();  
  337.   
  338.         mWindowParams = new WindowManager.LayoutParams();  
  339.         mWindowParams.gravity = Gravity.TOP;  
  340.         mWindowParams.x = 0;  
  341.         mWindowParams.y = y - mDragPoint + mCoordOffset;  
  342.   
  343.         mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;  
  344.         mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;  
  345.         mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE  
  346.                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE  
  347.                 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON  
  348.                 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN  
  349.                 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;  
  350.         mWindowParams.format = PixelFormat.TRANSLUCENT;  
  351.         mWindowParams.windowAnimations = 0;  
  352.           
  353.         Context context = getContext();  
  354.         ImageView v = new ImageView(context);  
  355. //        int backGroundColor = context.getResources().getColor(R.color.dragndrop_background);  
  356. //        v.setBackgroundColor(backGroundColor);  
  357.         v.setImageBitmap(bm);  
  358.         mDragBitmap = bm;  
  359.   
  360.         mWindowManager = (WindowManager)context.getSystemService("window");  
  361.         mWindowManager.addView(v, mWindowParams);  
  362.         mDragView = v;  
  363.     }  
  364.       
  365.     private void dragView(int x, int y) {  
  366.         if (mRemoveMode == SLIDE) {  
  367.             float alpha = 1.0f;  
  368.             int width = mDragView.getWidth();  
  369.             if (x > width / 2) {  
  370.                 alpha = ((float)(width - x)) / (width / 2);  
  371.             }  
  372.             mWindowParams.alpha = alpha;  
  373.         }  
  374.         if (mRemoveMode == FLING) {  
  375.             mWindowParams.x = x;  
  376.         }  
  377.         mWindowParams.y = y - mDragPoint + mCoordOffset;  
  378.         mWindowManager.updateViewLayout(mDragView, mWindowParams);  
  379.     }  
  380.       
  381.     private void stopDragging() {  
  382.         if (mDragView != null) {  
  383.             WindowManager wm = (WindowManager)getContext().getSystemService("window");  
  384.             wm.removeView(mDragView);  
  385.             mDragView.setImageDrawable(null);  
  386.             mDragView = null;  
  387.         }  
  388.         if (mDragBitmap != null) {  
  389.             mDragBitmap.recycle();  
  390.             mDragBitmap = null;  
  391.         }  
  392.     }  
  393.       
  394.     public void setDragListener(DragListener l) {  
  395.         mDragListener = l;  
  396.     }  
  397.       
  398.     public void setDropListener(DropListener l) {  
  399.         mDropListener = l;  
  400.     }  
  401.       
  402.     public void setRemoveListener(RemoveListener l) {  
  403.         mRemoveListener = l;  
  404.     }  
  405.   
  406.     public interface DragListener {  
  407.         void drag(int from, int to);  
  408.     }  
  409.     public interface DropListener {  
  410.         void drop(int from, int to);  
  411.     }  
  412.     public interface RemoveListener {  
  413.         void remove(int which);  
  414.     }  
  415. }  
 

<com.and.DragListview.TouchInterceptor

        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"        
        android:textSize="18sp"
        android:drawSelectorOnTop="false"
        android:fastScrollEnabled="true" /> 


如果想要实现源码音乐播放器那种顺畅的拖动效果,则需注意2点:

1.<!-- height of a normal list item in edit playlist mode -->
    <dimen name="normal_height">48dip</dimen>
    <!-- height of an expanded list item in edit playlist mode -->
    <dimen name="expanded_height">96dip</dimen>

后者的高度要为前者的2倍。

2.item对应的布局要在listview的item的bottom位置,即:

[java] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout   
  3.             xmlns:android="http://schemas.android.com/apk/res/android"  
  4.             android:orientation="vertical"  
  5.             android:layout_width="match_parent"  
  6.             android:layout_height="48dip">  
  7. <com.android.weather.CityListItemLayout   
  8.     android:id="@+id/item_layout"  
  9.     android:orientation="horizontal"  
  10.     android:layout_width="match_parent"  
  11.     android:layout_height="48dip"        
  12.     android:gravity="center_vertical"  
  13.     android:layout_alignParentBottom="true">  
  14. 。。。  
  15. </com.android.weather.CityListItemLayout>  
  16. </RelativeLayout>  
原创粉丝点击