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 }