android可拖動排序GridView實現

DragGridView繼承自GridView,當長按選中某個item進行拖動,放手更新GridView順序:

 

1.重寫onTouchEvent響應拖動事件:被按下時記錄按下坐標;拖動時更新被拖動視圖顯示;放開時更新排序

 

2.設置OnItemLongClickListener:響應長按選取拖動item,獲取被選中item bitmap,添加到窗口顯示

 

3.通過view.getDrawingCache()獲取被選中item的bitmap,用於繪制拖動的view

 

4.使用WindowManager來向窗口添加view,更新view顯示。關於WindowManagerService對窗口的組織方式,博客https://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 }

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *