转载

android可拖动排序GridView实现

经常使用今日头条、网易新闻的同学们应该都会注意到用于管理多个频道的可拖动排序GridView,下面介绍一下可拖动的DragGridView的实现方法。代码放在GitHub上https://github.com/zhaoyu87/DragGridView,需要的同学可以下载

android可拖动排序GridView实现

DragGridView继承自GridView,当长按选中某个item进行拖动,放手更新GridView顺序:

1.重写onTouchEvent响应拖动事件:被按下时记录按下坐标;拖动时更新被拖动视图显示;放开时更新排序

2.设置OnItemLongClickListener:响应长按选取拖动item,获取被选中item bitmap,添加到窗口显示

3.通过view.getDrawingCache()获取被选中item的bitmap,用于绘制拖动的view

4.使用WindowManager来向窗口添加view,更新view显示。关于WindowManagerService对窗口的组织方式,博客http://blog.csdn.net/luoshengyang/article/details/8498908有介绍,可以参考。

5. MotionEvent中的getX()为相对于容器的坐标,这里就是GridView;getRawX()为相对于整个屏幕的坐标

DragGridView实现如下,注释中有更详细的解释

  1 public class DragGridView extends GridView {   2     private static final int DRAG_IMG_SHOW = 1;   3     private static final int DRAG_IMG_NOT_SHOW = 0;   4     private static final String LOG_TAG = "DragGridView";   5     private static final float AMP_FACTOR = 1.2f;   6    7     /**被拖动的视图*/   8     private ImageView dragImageView;   9     private WindowManager.LayoutParams dragImageViewParams;  10     private WindowManager windowManager;  11     private boolean isViewOnDrag = false;  12   13     /**前一次拖动的位置*/  14     private int preDraggedOverPositon = AdapterView.INVALID_POSITION;  15     private int downRawX;  16     private int downRawY;  17   18     /**长按选中拖动item*/  19     private OnItemLongClickListener onLongClickListener = new OnItemLongClickListener(){  20   21         @Override  22         //长按item开始拖动  23         public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {  24   25             //记录长按item位置  26             preDraggedOverPositon = position;  27   28             //获取被长按item的drawing cache  29             view.destroyDrawingCache();  30             view.setDrawingCacheEnabled(true);  31             //通过被长按item,获取拖动item的bitmap  32             Bitmap dragBitmap = Bitmap.createBitmap(view.getDrawingCache());  33   34             //设置拖动item的参数  35             dragImageViewParams.gravity = Gravity.TOP | Gravity.LEFT;  36             //设置拖动item为原item 1.2倍  37             dragImageViewParams.width = (int)(AMP_FACTOR*dragBitmap.getWidth());  38             dragImageViewParams.height = (int)(AMP_FACTOR*dragBitmap.getHeight());  39             //设置触摸点为绘制拖动item的中心  40             dragImageViewParams.x = (downRawX - dragImageViewParams.width/2);  41             dragImageViewParams.y = (downRawY - dragImageViewParams.height/2);  42             dragImageViewParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE  43                                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE  44                                         | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON  45                                         | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;  46             dragImageViewParams.format = PixelFormat.TRANSLUCENT;  47             dragImageViewParams.windowAnimations = 0;  48   49             //dragImageView为被拖动item的容器,清空上一次的显示  50             if((int)dragImageView.getTag() == DRAG_IMG_SHOW) {  51                 windowManager.removeView(dragImageView);  52                 dragImageView.setTag(DRAG_IMG_NOT_SHOW);  53             }  54   55             //设置本次被长按的item  56             dragImageView.setImageBitmap(dragBitmap);  57   58             //添加拖动item到屏幕  59             windowManager.addView(dragImageView, dragImageViewParams);  60             dragImageView.setTag(DRAG_IMG_SHOW);  61             isViewOnDrag = true;  62   63             //设置被长按item不显示  64             ((GridViewAdapter)getAdapter()).hideView(position);  65             return true;  66         }  67     };  68   69     public DragGridView(Context context) {  70         super(context);  71         initView();  72     }  73   74     public DragGridView(Context context, AttributeSet attrs) {  75         super(context, attrs);  76         initView();  77     }  78   79     public DragGridView(Context context, AttributeSet attrs, int defStyleAttr) {  80         super(context, attrs, defStyleAttr);  81         initView();  82     }  83   84     public void initView() {  85         setOnItemLongClickListener(onLongClickListener);  86         //初始化显示被拖动item的image view  87         dragImageView = new ImageView(getContext());  88         dragImageView.setTag(DRAG_IMG_NOT_SHOW);  89         //初始化用于设置dragImageView的参数对象  90         dragImageViewParams = new WindowManager.LayoutParams();  91         //获取窗口管理对象,用于后面向窗口中添加dragImageView  92         windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);  93     }  94   95   96     @Override  97     public boolean onTouchEvent(MotionEvent ev) {  98   99         //被按下时记录按下的坐标 100         if(ev.getAction() == MotionEvent.ACTION_DOWN) { 101             //获取触摸点相对于屏幕的坐标 102             downRawX = (int)ev.getRawX(); 103             downRawY = (int)ev.getRawY(); 104         } 105         //dragImageView处于被拖动时,更新dragImageView位置 106         else if((ev.getAction() == MotionEvent.ACTION_MOVE) && (isViewOnDrag == true)) { 107             Log.i(LOG_TAG, "" + ev.getRawX() + " " + ev.getRawY()); 108             //设置触摸点为dragImageView中心 109             dragImageViewParams.x = (int)(ev.getRawX() - dragImageView.getWidth()/2); 110             dragImageViewParams.y = (int)(ev.getRawY() - dragImageView.getHeight()/2); 111             //更新窗口显示 112             windowManager.updateViewLayout(dragImageView, dragImageViewParams); 113             //获取当前触摸点的item position 114             int currDraggedPosition = pointToPosition((int)ev.getX(), (int)ev.getY()); 115             //如果当前停留位置item不等于上次停留位置的item,交换本次和上次停留的item 116             if((currDraggedPosition != AdapterView.INVALID_POSITION) && (currDraggedPosition != preDraggedOverPositon)) { 117                 ((GridViewAdapter)getAdapter()).swapView(preDraggedOverPositon, currDraggedPosition); 118                 preDraggedOverPositon = currDraggedPosition; 119             } 120         } 121         //释放dragImageView 122         else if((ev.getAction() == MotionEvent.ACTION_UP) && (isViewOnDrag == true)) { 123             ((GridViewAdapter)getAdapter()).showHideView(); 124             if((int)dragImageView.getTag() == DRAG_IMG_SHOW) { 125                 windowManager.removeView(dragImageView); 126                 dragImageView.setTag(DRAG_IMG_NOT_SHOW); 127             } 128             isViewOnDrag = false; 129         } 130         return super.onTouchEvent(ev); 131     } 132 }

GridViewAdapter继承自BaseAdapter:

1.提供showHideView、hideView两个方法用于显示和隐藏选中Item的Text

2.提供swapView方法用于拖动过程中更新GridView中item显示

 1 public class GridViewAdapter extends BaseAdapter {  2     private Context context;  3     private List<String> strList;  4     private int hidePosition = AdapterView.INVALID_POSITION;  5   6     public GridViewAdapter(Context context, List<String> strList) {  7         this.context = context;  8         this.strList = strList;  9     } 10  11     @Override 12     public int getCount() { 13         return strList.size(); 14     } 15  16     @Override 17     public String getItem(int position) { 18         return strList.get(position); 19     } 20  21     @Override 22     public long getItemId(int position) { 23         return position; 24     } 25  26     @Override 27     public View getView(int position, View convertView, ViewGroup parent) { 28         TextView view; 29         if(convertView == null) { 30             view = new TextView(context); 31         } 32         else { 33             view = (TextView)convertView; 34         } 35  36         //hide时隐藏Text 37         if(position != hidePosition) { 38             view.setText(strList.get(position)); 39         } 40         else { 41             view.setText(""); 42         } 43         view.setId(position); 44  45         return view; 46     } 47  48     public void hideView(int pos) { 49         hidePosition = pos; 50         notifyDataSetChanged(); 51     } 52  53     public void showHideView() { 54         hidePosition = AdapterView.INVALID_POSITION; 55         notifyDataSetChanged(); 56     } 57  58     public void removeView(int pos) { 59         strList.remove(pos); 60         notifyDataSetChanged(); 61     } 62  63     //更新拖动时的gridView 64     public void swapView(int draggedPos, int destPos) { 65         //从前向后拖动,其他item依次前移 66         if(draggedPos < destPos) { 67             strList.add(destPos+1, getItem(draggedPos)); 68             strList.remove(draggedPos); 69         } 70         //从后向前拖动,其他item依次后移 71         else if(draggedPos > destPos) { 72             strList.add(destPos, getItem(draggedPos)); 73             strList.remove(draggedPos+1); 74         } 75         hidePosition = destPos; 76         notifyDataSetChanged(); 77     } 78 }
正文到此结束
Loading...