android可拖動排序GridView實現


經常使用今日頭條、網易新聞的同學們應該都會注意到用於管理多個頻道的可拖動排序GridView,下面介紹一下可拖動的DragGridView的實現方法。代碼放在GitHub上https://github.com/zhaoyu87/DragGridView,需要的同學可以下載

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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM