Android学习系列--App列表之拖拽ListView(下)
接着上篇Android学习系列(10)--App列表之拖拽ListView(上)我们继续实现ListView的拖拽效果。
7.重写onTouchEvent()方法。
在这个方法中我们主要是处理拖动和放下。
拖动是选中项的影像随着手指滑动;放下是在拖动结束的时候交换数据。
方法的整体结构如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/** * 触摸事件 */@Overridepublic boolean onTouchEvent(MotionEvent ev) { //如果dragmageView为空,说明拦截事件中已经判定仅仅是点击,不是拖动,返回 //如果点击的是无效位置,返回,需要重新判断 if(dragImageView!=null&&dragPosition!=INVALID_POSITION){ int action = ev.getAction(); switch(action){ case MotionEvent.ACTION_UP: int upY = (int)ev.getY(); //释放拖动影像 stopDrag(); //放下后,判断位置,实现相应的位置删除和插入 onDrop(upY); break; case MotionEvent.ACTION_MOVE: int moveY = (int)ev.getY(); //拖动影像 onDrag(moveY); break; default:break; } return true; } //这个返回值能够实现selected的选中效果,如果返回true则无选中效果 return super.onTouchEvent(ev);} |
8.拖动影像。
拖动的时候,我们调用了onDrag(int y)方法,主要做的事情是,让选中项的影像随这手指滑动起来。如下:
|
1
2
3
4
5
6
7
8
|
if(dragImageView!=null){ //设置一点点的透明度 windowParams.alpha = 0.8f; //更新y坐标位置 windowParams.y = y - dragPoint + dragOffset; //更新界面 windowManager.updateViewLayout(dragImageView, windowParams);} |
当数据集合很大的时候,还需要在拖动到上部区域或者下部区域的时候滚动列表,使用ListView自带的方法setSelectionFromTop()。
一个可以滚动的拖拽列表雏形就出来了,最终onDrag()方法代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/** * 拖动执行,在Move方法中执行 * @param y */public void onDrag(int y){ if(dragImageView!=null){ windowParams.alpha = 0.8f; windowParams.y = y - dragPoint + dragOffset; windowManager.updateViewLayout(dragImageView, windowParams); } //为了避免滑动到分割线的时候,返回-1的问题 int tempPosition = pointToPosition(0, y); if(tempPosition!=INVALID_POSITION){ dragPosition = tempPosition; } //滚动 int scrollHeight = 0; if(y<upScrollBounce){ scrollHeight = 8;//定义向上滚动8个像素,如果可以向上滚动的话 }else if(y>downScrollBounce){ scrollHeight = -8;//定义向下滚动8个像素,,如果可以向上滚动的话 } if(scrollHeight!=0){ //真正滚动的方法setSelectionFromTop() setSelectionFromTop(dragPosition, getChildAt(dragPosition-getFirstVisiblePosition()).getTop()+scrollHeight); }} |
拖动的效果如下:
9.放下影像,数据更新。
上面实现了拖动的效果,放下影像后:
1)我们要获取放下的位置是数据集合的哪一项;
2)在放下位置项插入拖动数据,并删除拖动数据原位置项
这些处理写在了onDrop()方法中,在ACTION_UP动作中执行,代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/** * 拖动放下的时候 * @param y */public void onDrop(int y){ //获取放下位置在数据集合中position //定义临时位置变量为了避免滑动到分割线的时候,返回-1的问题,如果为-1,则不修改dragPosition的值,急需执行,达到跳过无效位置的效果 int tempPosition = pointToPosition(0, y); if(tempPosition!=INVALID_POSITION){ dragPosition = tempPosition; } //超出边界处理 if(y<getChildAt(0).getTop()){ //超出上边界,设为最小值位置0 dragPosition = 0; }else if(y>getChildAt(getChildCount()-1).getBottom()){ //超出下边界,设为最大值位置,注意哦,如果大于可视界面中最大的View的底部则是越下界,所以判断中用getChildCount()方法 //但是最后一项在数据集合中的position是getAdapter().getCount()-1,这点要区分清除 dragPosition = getAdapter().getCount()-1; } //数据更新 if(dragPosition>0&&dragPosition<getAdapter().getCount()){ @SuppressWarnings("unchecked") ArrayAdapter<String> adapter = (ArrayAdapter<String>)getAdapter(); String dragItem = adapter.getItem(dragSrcPosition); //删除原位置数据项 adapter.remove(dragItem); //在新位置插入拖动项 adapter.insert(dragItem, dragPosition); }} |
放下时我们就能实现数据的更新了,拖动后的数据状态就能保存下来(虽然保存在dapter中了)。效果如下:
我处理了一下(在dapter的方法中定义getList()方法得到adpter中List<String>,使用toString()方法连接起来),把adapter的结果输出来看看:
至于数据的详细处理或者保存,不是本文拖拽的内容,只要抓住adapter集合分析应该很容易的。
三、拓展
10.分组拖拽拓展。
前面我们一直在数据源中添加了分组标签A组,B组的,下面我们就把数据分成A组,B组,更详细内容可参考 Android学习系列(9)--App列表之分组ListView。
1)定义分组标签样式布局drag_list_item_tag.xml。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<?xml version="1.0" encoding="utf-8"?> android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#555555" android:padding="5dip" android:paddingLeft="10dip"> <!--文本框的ID保持不变--> <TextView android:id="@+id/drag_list_item_text" android:layout_width="wrap_content" android:layout_height="20dip" android:textColor="#ffffff" android:gravity="center_vertical"/> <!--去除来右边拖拽图像,分组标签是不能随意拖动的--></LinearLayout> |
2)修改DragListAdapter中getView()方法。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Overridepublic View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if(groupKey.contains(getItem(position))){ //如果是分组标签,就加载分组标签的布局文件,两个布局文件显示效果不同 view = LayoutInflater.from(getContext()).inflate(R.layout.drag_list_item_tag, null); }else{ //如果是正常数据项标签,就加在正常数据项的布局文件 view = LayoutInflater.from(getContext()).inflate(R.layout.drag_list_item, null); } TextView textView = (TextView)view.findViewById(R.id.drag_list_item_text); textView.setText(getItem(position)); return view;} |
3)禁用分组标签项的响应事件,在DragListAapter中重写方法isEnable()。
刚好因为在分组标签中去掉了拖拽图像,所以点击在分组标签中的话,dragImageView为空,不会有被拖动的效果了,这就是前面说的顺手的一个妙用了。
|
1
2
3
4
5
6
7
8
|
@Overridepublic boolean isEnabled(int position) { if(groupKey.contains(getItem(position))){ //如果是分组标签,返回false,不能选中,不能点击 return false; } return super.isEnabled(position);} |
4)标签项是不能拖动位置的,所以我们要修改一下onDrop()中的上边界控制。
|
1
2
3
4
5
6
7
8
|
//上边界改为1if(y<getChildAt(1).getTop()){ //超出上边界 dragPosition = 1;}else if(y>getChildAt(getChildCount()-1).getBottom()){ //超出下边界 dragPosition = getAdapter().getCount()-1;} |
最终效果为:
至此,拖拽ListView的实现结束了。
如果您发现有什么bug,联系我。
难得的上传一下代码,没找到博客园上传文件的地方,我放到了github上,下载地址是: https://github.com/fjtianxia/qianxudetianxia。
Android学习系列--App列表之拖拽ListView(下)的更多相关文章
- Android学习系列--App列表之拖拽ListView(上)
研究了很久的拖拽ListView的实现,受益良多,特此与尔共飨. 鉴于这部分内容网上的资料少而简陋,而具体的实现过程或许对大家才有帮助,为了详尽而不失真,我们一步一步分析,分成两篇文章. 一 ...
- Android学习系列(11)--App列表之拖拽ListView(下)
接着上篇Android学习系列(10)--App列表之拖拽ListView(上)我们继续实现ListView的拖拽效果. 7.重写onTouchEvent()方法. 在这个方法中我们主要是处理 ...
- Android学习系列(10)--App列表之拖拽ListView(上)
研究了很久的拖拽ListView的实现,受益良多,特此与尔共飨. 鉴于这部分内容网上的资料少而简陋,而具体的实现过程或许对大家才有帮助,为了详尽而不失真,我们一步一步分析,分成两篇文章. ...
- Android学习系列(12)--App列表之拖拽GridView
根据前面文章中ListView拖拽的实现原理,我们也是很容易实现推拽GridView的,下面我就以相同步骤实现基本的GridView拖拽效果. 因为GridView不用做分组处理,代码处理起来 ...
- 【转】Android学习系列–App离线下载功能实现
原文:http://www.cnblogs.com/qianxudetianxia/archive/2011/07/20/2108965.html 宜未雨而绸缪,毋临渴而掘井.----朱用纯<治 ...
- Android学习系列(15)--App列表之游标ListView(索引ListView)
游标ListView,提供索引标签,使用户能够快速定位列表项. 也可以叫索引ListView,有的人称也为Tweaked ListView,可能更形象些吧. 一看图啥都懂了: 1. ...
- Android学习系列(17)--App列表之圆角ListView(续)
http://www.cnblogs.com/qianxudetianxia/archive/2011/09/19/2068760.html 本来这篇文章想并到上篇Android学习系列(16)- ...
- Android学习系列(18)--App工程结构搭建
本文算是一篇漫谈,谈一谈关于Android开发中工程初始化的时候如何在初期我们就能搭建一个好的架构. 关于android架构,因为手机的限制,目前我觉得也确实没什么大谈特谈的,但是从开发的 ...
- Android学习系列(37)--App调试内存泄露之Context篇(下)
接着<Android学习系列(36)--App调试内存泄露之Context篇(上)>继续分析. 5. AsyncTask对象 我N年前去盛大面过一次试,当时面试官极力推荐我使用AsyncT ...
随机推荐
- XJOI 3629 非严格次小生成树(pqq的礼物)
题目描述: 有一天,pqq准备去给×i×准备礼物,他有一些礼品准备包装一下,他用线将这些礼物连在一起,不同的礼物因为风格不同所以连接它们需要不同价值的线.风格差异越大,价格越大(所以两个礼物之间只有一 ...
- CodeForces 376F Tree and Queries(假·树上莫队)
You have a rooted tree consisting of n vertices. Each vertex of the tree has some color. We will ass ...
- 理解Javascript中的事件绑定与事件委托
最近在深入实践js中,遇到了一些问题,比如我需要为动态创建的DOM元素绑定事件,那么普通的事件绑定就不行了,于是通过上网查资料了解到事件委托,因此想总结一下js中的事件绑定与事件委托. 事件绑定 ...
- 在Android模拟器里安装apk
[原文]http://Android.tgbus.com/android/tutorial/201104/349532.shtml 1.运行SDK Manager,选择模拟器,并运行模拟器. 2.将需 ...
- github 上中国互联网公司的开源项目
github上 那个 watch和 follow功能 不太好用啊. 是我用的 不好,还是 怎么的.有时候 找不到 watch 和 follow. 秉持 开源 精神,省的大家 和 我 查找. 我只关注 ...
- SSH密钥登陆
参考: SSH公钥登录原理 比如git可以生成公钥,然后用有权限的账户把他加到仓库上,以后就可以通过公钥登陆了.不需要像https那样需要有账号,但是权限管理就不细了. 有时候如果仓库上添加了多个公钥 ...
- PXE-cobbler 无人值守装机------续
上篇学习了cobbler pxe 安装的大致流程以及采用默认分区方式安装centos7系统. 这里深入学习ks文件的具体参数 . ks.cfg文件又叫kickstart.cfg文件,主要被用于linu ...
- 最大子段和问题(dp)
最大子段和问题 给出一个整数数组a(正负数都有),如何找出一个连续子数组(可以一个都不取,那么结果为0),使得其中的和最大? 例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4, ...
- 二 ,Smarty模板技术/引擎——变量操作(1)
1,基本变量 $smarty->assign('data1',3); $smarty->assign('data2',3.45); $smarty->assign('data3',' ...
- 20 行代码极速为 App 加上聊天功能
现在很多 App 都需要集成 IM 功能,今天就为大家分享一下集成 IM 基本功能的步骤.本文内容以 JMessage 为例.极光 IM ( JMessage ) = 极光推送 ( JPush ) + ...