经常使用今日头条、网易新闻的同学们应该都会注意到用于管理多个频道的可拖动排序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 }

android可拖动排序GridView实现的更多相关文章

  1. Android 实现高仿iOS桌面效果之可拖动的GridView(上)

    转载请标明出处:http://blog.csdn.net/sk719887916/article/details/40074663,作者:skay      最近项目中遇到一个LIstview的拖动效 ...

  2. RecyclerView-- 侧滑删除和拖动排序

    实现这么个功能我们不需要再去继承RecyclerView,只需要去了解ItemTouchHelper这个类即可,接下来我们就去看看都有些什么 ItemTouchHelper.Callback 默认需要 ...

  3. ItemTouchHelper(实现RecyclerView上添加拖动排序与滑动删除的所有事情)

    简单介绍: ItemTouchHelper是一个强大的工具,它处理好了关于在RecyclerView上添加拖动排序与滑动删除的所有事情.它是RecyclerView.ItemDecoration的子类 ...

  4. RecyclerView实现拖动排序和滑动删除功能

    RecyclerView 的拖动排序需要借助一下 ItemTouchHelper 这个类,ItemTouchHelper 类是 Google 提供的一个支持 RecyclerView 滑动和拖动的一个 ...

  5. 基于Metronic的Bootstrap开发框架经验总结(13)--页面链接收藏夹功能的实现2(利用Sortable进行拖动排序)

    在上篇随笔<基于Metronic的Bootstrap开发框架经验总结(12)--页面链接收藏夹功能的实现>上,我介绍了链接收藏夹功能的实现,以及对收藏记录的排序处理.该篇随笔主要使用功能按 ...

  6. 锋利的jQuery-7--query ui效果库--拖动排序插件sortable

    一个简单的拖动排序效果,具体请参看jQuery ui官网demo. jquery ui :http://jqueryui.com/ sortable例子:http://jqueryui.com/sor ...

  7. Android 可拖动列表项的ListView

    需求分析 一个界面内两个ListView 我关注的栏目列表 上面的要长按后可拖动排序 点击减号后列表项消失 下面列表增加一行 同时存储相应字符串到本地作为标记 未关注栏目列表 普通ListView 点 ...

  8. Android实现自适应正方形GridView

    Android实现自适应正方形GridView  

  9. Element-UI标签页el-tabs组件的拖动排序实现

    ElementUI的标签页组件支持动态添加删除,如下图: 但是这个组件不支持标签之间的拖动排序.那么我们自己怎样实现这个功能呢? 有一个叫vuedraggable的组件(https://github. ...

随机推荐

  1. 凯恩斯主义VS货币主义

    Milton Friedman在1960年代后期以及整个1970年代,到处不知疲倦地像传教士一般地宣讲他的货币主义.当时,美联储成员几乎清一色地是凯恩斯主义者.你可以想像Friedman的对手是多么强 ...

  2. Delphi获取当前系统时间(使用API函数GetSystemTime)

    在开发应用程序时往往需要获取当前系统时间.尽管Y2K似乎已经平安过去,但在我们新开发的应用程序中还是要谨慎处理“时间”问题. 在<融会贯通--Delphi4.0实战技巧>(以下简称“该书” ...

  3. printdir-deldir-bmp

    #include<unistd.h> #include<stdio.h> #include<dirent.h> #include<string.h> # ...

  4. 用Python写的一个多线程机器人聊天程序

    本人是从事php开发的, 近来想通过php实现即时通讯(兼容windows).后来发现实现起来特别麻烦, 就想到python.听说这家伙在什么地方都能发挥作用.所以想用python来做通讯模块...所 ...

  5. Day1_算法分析方法

    课堂笔记: 程序执行效率影响因子: 输入:评估时使用最坏情况输入 输入大小:考虑n渐进∞ 机器执行效率: 忽略 两种排序算法比较 插入排序n2 归并排序nlgn 递归 技能1:评估多项式的时间级数θ ...

  6. Android 给Button加个监听

    1.日期设置控件:DatePickerDialog 2.时间设置控件:TimePickerDialog 实例代码 1.页面添加两个Button,单击分别显示日期设置控件和时间设置控件,还是有TextV ...

  7. Python学习笔记2-Python神奇的语法和格式化输出

    先来看一个例子: class Fish: hungry=True def eat(self,food): if food is not None: self.hungry=False class Us ...

  8. Linux学习之第十九、条件判断

    原文地址:http://vbird.dic.ksu.edu.tw/linux_basic/0340bashshell-scripts_4.php 条件判断式 只要讲到『程序』的话,那么条件判断式,亦即 ...

  9. 面试题之——将文件夹下java文件写入到新的文件夹,并修改扩展名

    题目:将d:/code/java文件夹下的所有.java文件复制到d:/code/java/jad文件夹下并且将原来的文件的扩展名.java改为.jad 源代码: package com.zyh.in ...

  10. 自定义构造方法和description方法

    知识回顾在第5讲中已经介绍了如何定义类和创建并初始化对象,比如有Student这个类1.Student.h 1 #import <Foundation/Foundation.h>23@in ...