接着上篇Android学习系列(10)--App列表之拖拽ListView(上)我们继续实现ListView的拖拽效果。
7.重写onTouchEvent()方法。
     在这个方法中我们主要是处理拖动和放下。
     拖动是选中项的影像随着手指滑动;放下是在拖动结束的时候交换数据。
     方法的整体结构如下:
  1. /**
  2. * 触摸事件
  3. */
  4. @Override
  5. public boolean onTouchEvent(MotionEvent ev) {
  6. //如果dragmageView为空,说明拦截事件中已经判定仅仅是点击,不是拖动,返回
  7. //如果点击的是无效位置,返回,需要重新判断
  8. if(dragImageView!=null&&dragPosition!=INVALID_POSITION){
  9. int action = ev.getAction();
  10. switch(action){
  11. case MotionEvent.ACTION_UP:
  12. int upY = (int)ev.getY();
  13. //释放拖动影像
  14. stopDrag();
  15. //放下后,判断位置,实现相应的位置删除和插入
  16. onDrop(upY);
  17. break;
  18. case MotionEvent.ACTION_MOVE:
  19. int moveY = (int)ev.getY();
  20. //拖动影像
  21. onDrag(moveY);
  22. break;
  23. default:break;
  24. }
  25. return true;
  26. }
  27. //这个返回值能够实现selected的选中效果,如果返回true则无选中效果
  28. return super.onTouchEvent(ev);
  29. }

复制代码

8.拖动影像。
      拖动的时候,我们调用了onDrag(int y)方法,主要做的事情是,让选中项的影像随这手指滑动起来。如下:

  1. if(dragImageView!=null){
  2. //设置一点点的透明度
  3. windowParams.alpha = 0.8f;
  4. //更新y坐标位置
  5. windowParams.y = y - dragPoint + dragOffset;
  6. //更新界面
  7. windowManager.updateViewLayout(dragImageView, windowParams);
  8. }

复制代码

当数据集合很大的时候,还需要在拖动到上部区域或者下部区域的时候滚动列表,使用ListView自带的方法setSelectionFromTop()。
       一个可以滚动的拖拽列表雏形就出来了,最终onDrag()方法代码如下:

  1. /**
  2. * 拖动执行,在Move方法中执行
  3. * @param y
  4. */
  5. public void onDrag(int y){
  6. if(dragImageView!=null){
  7. windowParams.alpha = 0.8f;
  8. windowParams.y = y - dragPoint + dragOffset;
  9. windowManager.updateViewLayout(dragImageView, windowParams);
  10. }
  11. //为了避免滑动到分割线的时候,返回-1的问题
  12. int tempPosition = pointToPosition(0, y);
  13. if(tempPosition!=INVALID_POSITION){
  14. dragPosition = tempPosition;
  15. }
  16. //滚动
  17. int scrollHeight = 0;
  18. if(y<upScrollBounce){
  19. scrollHeight = 8;//定义向上滚动8个像素,如果可以向上滚动的话
  20. }else if(y>downScrollBounce){
  21. scrollHeight = -8;//定义向下滚动8个像素,,如果可以向上滚动的话
  22. }
  23. if(scrollHeight!=0){
  24. //真正滚动的方法setSelectionFromTop()
  25. setSelectionFromTop(dragPosition, getChildAt(dragPosition-getFirstVisiblePosition()).getTop()+scrollHeight);
  26. }
  27. }

复制代码

拖动的效果如下:
<ignore_js_op>
9.放下影像,数据更新。
      上面实现了拖动的效果,放下影像后:
      1)我们要获取放下的位置是数据集合的哪一项;
      2)在放下位置项插入拖动数据,并删除拖动数据原位置项
      这些处理写在了onDrop()方法中,在ACTION_UP动作中执行,代码如下:
  1. /**
  2. * 拖动放下的时候
  3. * @param y
  4. */
  5. public void onDrop(int y){
  6. //获取放下位置在数据集合中position
  7. //定义临时位置变量为了避免滑动到分割线的时候,返回-1的问题,如果为-1,则不修改dragPosition的值,急需执行,达到跳过无效位置的效果
  8. int tempPosition = pointToPosition(0, y);
  9. if(tempPosition!=INVALID_POSITION){
  10. dragPosition = tempPosition;
  11. }
  12. //超出边界处理
  13. if(y<getChildAt(0).getTop()){
  14. //超出上边界,设为最小值位置0
  15. dragPosition = 0;
  16. }else if(y>getChildAt(getChildCount()-1).getBottom()){
  17. //超出下边界,设为最大值位置,注意哦,如果大于可视界面中最大的View的底部则是越下界,所以判断中用getChildCount()方法
  18. //但是最后一项在数据集合中的position是getAdapter().getCount()-1,这点要区分清除
  19. dragPosition = getAdapter().getCount()-1;
  20. }
  21. //数据更新
  22. if(dragPosition>0&&dragPosition<getAdapter().getCount()){
  23. @SuppressWarnings("unchecked")
  24. ArrayAdapter<String> adapter = (ArrayAdapter<String>)getAdapter();
  25. String dragItem = adapter.getItem(dragSrcPosition);
  26. //删除原位置数据项
  27. adapter.remove(dragItem);
  28. //在新位置插入拖动项
  29. adapter.insert(dragItem, dragPosition);
  30. }
  31. }

复制代码

放下时我们就能实现数据的更新了,拖动后的数据状态就能保存下来(虽然保存在dapter中了)。效果如下:
<ignore_js_op>      我处理了一下(在dapter的方法中定义getList()方法得到adpter中List<String>,使用toString()方法连接起来),把adapter的结果输出来看看:

<ignore_js_op>       至于数据的详细处理或者保存,不是本文拖拽的内容,只要抓住adapter集合分析应该很容易的。
三、拓展
10.分组拖拽拓展。
      前面我们一直在数据源中添加了分组标签A组,B组的,下面我们就把数据分成A组,B组,更详细内容可参考 Android学习系列(9)--App列表之分组ListView。
      1)定义分组标签样式布局drag_list_item_tag.xml。
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="wrap_content"
  5. android:background="#555555"
  6. android:padding="5dip"
  7. android:paddingLeft="10dip">
  8. <!--文本框的ID保持不变-->
  9. <TextView
  10. android:id="@+id/drag_list_item_text"
  11. android:layout_width="wrap_content"
  12. android:layout_height="20dip"
  13. android:textColor="#ffffff"
  14. android:gravity="center_vertical"/>
  15. <!--去除来右边拖拽图像,分组标签是不能随意拖动的-->
  16. </LinearLayout>

复制代码

2)修改DragListAdapter中getView()方法。

  1. @Override
  2. public View getView(int position, View convertView, ViewGroup parent) {
  3. View view = convertView;
  4. if(groupKey.contains(getItem(position))){
  5. //如果是分组标签,就加载分组标签的布局文件,两个布局文件显示效果不同
  6. view = LayoutInflater.from(getContext()).inflate(R.layout.drag_list_item_tag, null);
  7. }else{
  8. //如果是正常数据项标签,就加在正常数据项的布局文件
  9. view = LayoutInflater.from(getContext()).inflate(R.layout.drag_list_item, null);
  10. }
  11. TextView textView = (TextView)view.findViewById(R.id.drag_list_item_text);
  12. textView.setText(getItem(position));
  13. return view;
  14. }

复制代码

3)禁用分组标签项的响应事件,在DragListAapter中重写方法isEnable()。
             刚好因为在分组标签中去掉了拖拽图像,所以点击在分组标签中的话,dragImageView为空,不会有被拖动的效果了,这就是前面说的顺手的一个妙用了。

  1. @Override
  2. public boolean isEnabled(int position) {
  3. if(groupKey.contains(getItem(position))){
  4. //如果是分组标签,返回false,不能选中,不能点击
  5. return false;
  6. }
  7. return super.isEnabled(position);
  8. }

复制代码

4)标签项是不能拖动位置的,所以我们要修改一下onDrop()中的上边界控制。

  1. //上边界改为1
  2. if(y<getChildAt(1).getTop()){
  3. //超出上边界
  4. dragPosition = 1;
  5. }else if(y>getChildAt(getChildCount()-1).getBottom()){
  6. //超出下边界
  7. dragPosition = getAdapter().getCount()-1;
  8. }

复制代码

最终效果为:

<ignore_js_op>     至此,拖拽ListView的实现结束了。
    如果您发现有什么bug,联系我。

Android学习系列(11)--App列表之拖拽ListView(下)相关推荐

  1. Android学习系列(10)--App列表之拖拽ListView(上)

    研究了很久的拖拽ListView的实现,受益良多,特此与尔共飨.       鉴于这部分内容网上的资料少而简陋,而具体的实现过程或许对大家才有帮助,为了详尽而不失真,我们一步一步分析,分成两篇文章. ...

  2. Android学习系列(15)--App列表之游标ListView(索引ListView)

    游标ListView,提供索引标签,使用户能够快速定位列表项.       也可以叫索引ListView,有的人称也为Tweaked ListView,可能更形象些吧.       一看图啥都懂了: ...

  3. App列表之拖拽ListView(上)

    一.准备. 1.需求问题 初步:实现列表的拖拽效果(可参考Android源码下packages/apps/Music中的播放列表TouchInterceptor.java源码). (提前说明一下,本文 ...

  4. Android学习系列(16)--App列表之圆角ListView

    有些东西看多了,就厌烦了:extjs对我这种感觉最为强烈.甚至,有时觉得设计之殇是审美疲劳. 直角看多了,就想看看圆角,不知何时,这几年刮起了一阵阵的圆角设计风:CSS新标准纳入圆角元素,iphone ...

  5. Android学习系列(34)--App应用之发布各广告平台版本

    Android的广告平台是很多的,各市场对各平台的接受程度是不一样的,Android的开发者如果想集成广告基本要考虑下面两个问题: (1)集成什么广告,会赚钱? (2)集成什么广告,不会被市场拒绝? ...

  6. Android学习系列(27)--App缓存管理

    随笔- 53 文章- 10 评论- 1064 Android学习系列(27)--App缓存管理 无论大型或小型应用,灵活的缓存可以说不仅大大减轻了服务器的压力,而且因为更快速的用户体验而方便了用户. ...

  7. Android学习系列(7)--App轮询服务器消息

    这篇文章是android开发人员的必备知识. 1.轮询服务器      一般的应用,定时通知消息可以采用轮询的方法从服务器拿取消息,当然实时消息通知的话,建议采用推送服务.     其中需要注意轮询的 ...

  8. Android学习系列(19)--App离线下载

    宜未雨而绸缪,毋临渴而掘井.----朱用纯<治家格言> 离线下载,在有网络的情况下下载服务器数据,以便无网络时也能阅读,就是离线阅读. 离线下载的功能点如下:       1.下载管理(开 ...

  9. Android学习系列(22)--App主界面比较

    本文算是一篇漫谈,谈一谈当前几个流行应用的主界面布局,找个经典的布局我们自己也来实现一个. 不是为了追求到底有多难,而是为了明白我们确实需要这么做.  走个题,android的UI差异化市场依然很大, ...

最新文章

  1. vc mysql utf8_C/C++ 连接 MySQL (VC 版)
  2. 企业网络推广浅析外包企业网络推广如何有效布局关键词优化?
  3. EasyUI中ToolTip提示框的简单使用
  4. Mono源码学习笔记:Console类(四)
  5. C++实现图的深度优先遍历和广度优先遍历
  6. QT-QPainter绘制曲线等基本图形
  7. ubuntu中怎么打开python_如何在Linux Ubuntu 16.04下安装及打开PyCharm
  8. Java Bean + 注册验证
  9. httpclient 手写
  10. 多个服务器数据互通_数据中心
  11. System.Diagnostics.debug.Assert(条件)的使用
  12. pythotn基础篇——条件分支与循环--4
  13. M1芯片电脑SVN安装
  14. Spring的两种定时器
  15. 用火箭送快递?淘宝宣布联合蓝箭航天起启动“宝箭”计划
  16. 股票行情图的绘制,分时图和闪电图
  17. markdown 删除线
  18. spring基于注解的AOP配置 中的环绕通知 步骤写法
  19. 合肥工业大学计算机学院任恒,合肥工业大学计算机与信息学院导师教师师资介绍简介-△张玉红...
  20. ASR自动语音识别技术

热门文章

  1. 激光雷达厂商速腾聚创获3亿元融资,阿里菜鸟、上汽,北汽入股
  2. 波士顿动力机器狗解锁“自动驾驶”,会跑步的Atlas真的很稳
  3. 全套安全从业人员必备工具(建议大家收藏这个帖子)
  4. 老男孩第31期杨海学习Linux决心书
  5. 一条空间不足报警的分析
  6. 简单识别 RESTful 接口
  7. CentOS6安装Cisco模拟器Dynamips
  8. cisco 次优路由
  9. 解决Centos7 yum 出现could not retrieve mirrorlist 错误
  10. thinkphp-volist4