这篇博客主要讲解如何代码实现拖动图标功能。阅读本篇博客之前请先阅读上一篇博客,了解一下事件分发机制的一些要点。

Android新体会(一)通过仿桌面实现图标拖动了解事件分发机制

然后是demo地址https://github.com/huangwanjie/TableImitate/tree/develop

效果图

实现拖动的actvtiy包含一个ViewPager和一个CellDragLayout。ViewPager包含两个fragment,fragment中的布局有一个RecyclerView。CellDragLayout是实现图标移动的类。首先看一下布局activity布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ui.activity.MainActivity"><FrameLayoutandroid:id="@+id/fl_under"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v4.view.ViewPagerandroid:id="@+id/vp_cells"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginTop="100dp"/></FrameLayout><com.hwj.test.tabledrag.celldrag.CellDragLayoutandroid:id="@+id/cdl_drag"android:layout_width="match_parent"android:layout_height="match_parent"/></RelativeLayout>

然后看fragment布局

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/rv_cells"android:layout_width="match_parent"android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>

最后RecyclerView的item的布局:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="100dp"><ImageView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/iv_item"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:scaleType="fitXY"/>
</FrameLayout>

说一下实现的大概思路:

1.长按RecyclerView中的item,然后在CellDragLayout上新建一个ImageView,把item的bitmap给到ImageView,同时将item设为View.INVISIBLE.

2.让ImageView随着CellDragLayout接收到的Move事件而移动。

3.松开手后remove掉ImageView,同时item设为View.VISIBLE。

这里的重点主要是第一步和第二步的衔接。上一篇博客中提到,在ViewGroup事件分发中,Down事件是整个事件的开始,消费了Down时间的view,ViewGroup在不拦截的情况下会把后续的事件都交给该view去处理,不再访问分发到其它子view,也就是在事件分发的流程中消费事件都是同一个View。所以在正常事件分发流程中,item获取了并消费事件之后,RelativeLayout不可能在本次触摸事件结束之后将事件在分发给CellDraglayout。因此实际上我们需要解决的问题是,CellDragLayout和item都必须能接收和消费到相同的事件。由于CellDragLayout布局中的最上层,所以它能很容易的获取到事件,并进行消费,但是消费过后RelativeLayout不会把事件间接地分发给item了。所以按下的时候,先判断该位置是否在ViewPager所在的区域中,如果是,CellDragLayout在onTouchEvent(MotionEvent event)中消费事件,同时需要主动地将事件分发给activity_main.xml中的FrameLayout,调用FrameLayout的dispatchTouchEvent(MotionEvent event)方法,把CellDragLayout接收到的event传进去,item自然就可以获取到事件了。

下面把CellDragLayout中重写的onTouchEvent()方法贴出来

public boolean onTouchEvent(MotionEvent event) {Log.i("onTouchEvent", event.toString());if (actionDownRect == null){ //1return false;}currentTouchX = event.getX();currentTouchY = event.getY();if (event.getAction() == MotionEvent.ACTION_DOWN){ //2if (!actionDownRect.contains((int) event.getRawX(), (int) event.getRawY())) {return false;}}if (moveView == null){ //3deleteCellHelper.transferTouchEvent(event);return true;}switch (event.getAction()){case MotionEvent.ACTION_MOVE: //4moveView.setTranslationX(currentTouchX - (moveView.getX() + moveView.getWidth() / 2) + moveView.getTranslationX());moveView.setTranslationY(currentTouchY - (moveView.getY() + moveView.getHeight() / 2) + moveView.getTranslationY());onMoveState((int)(event.getX()), (int)(event.getY()));break;case MotionEvent.ACTION_UP:onUpState((int)(event.getX()), (int)(event.getY()));break;default:break;}return true;}

注释1中的actionDownRect是ViewPager相对于CellDragLayout的区域,要是没有设置该区域就不消费事件。注释2中判断触点是否在actionDownRect之中,不在就不消费事件。注释3中moveView是在CellDragLayout上移动的控件,在item触发长按是创建,为空表示还没有触发,侧通过一个辅助类DeleteCellHelper调用transferTouchEvent(MotionEvent event),把事件传递出去。注释4是在长按时候moveView创建之后执行,使moveView根据触点移动。下面看看DeleteCellHelper类部分代码:

public class DeleteCellHelper<T> {private CellDragLayout dragLayout;private View underLayout;private T content;View view;public DeleteCellHelper(CellDragLayout dragLayout,View underLayout){this.dragLayout = dragLayout;this.underLayout = underLayout;dragLayout.setDeleteCellHelper(this);}public void setDownActionRect(Rect rect){dragLayout.setActionDownRect(rect);}public void onAction(View view, T content){this.view = view;this.content = content;viewCopy(view);view.setVisibility(View.INVISIBLE);}private void viewCopy(View view){Bitmap bitmap = ViewUtil.getViewBitmap(view);ImageView ivCopy = new ImageView(view.getContext());ivCopy.setClickable(false);Rect rect = new Rect();view.getGlobalVisibleRect(rect);LayoutParams lp = new LayoutParams(view.getWidth(), view.getHeight());lp.leftMargin = rect.left;lp.topMargin = rect.top - (int) dragLayout.getX();ivCopy.setLayoutParams(lp);ivCopy.setImageBitmap(bitmap);dragLayout.addMoveView(ivCopy, bitmap);}public void cancle(){view.setVisibility(View.VISIBLE);if (deleteListenter != null){deleteListenter.onCancle();}}public void deleted(){if (deleteListenter != null){deleteListenter.onDeteled(content);}}private DeleteListenter deleteListenter;public void setDeleteListenter(DeleteListenter deleteListenter){this.deleteListenter = deleteListenter;}public void transferTouchEvent(MotionEvent event){underLayout.dispatchTouchEvent(event);}public interface DeleteListenter<T>{void onCancle();void onDeteled(T content);}
}

underLayout是demo中的activity_main.xml的FrameLayout,创建DeleteCellHelper时把该对象传进去。item在长按之后调用onAtion(View v, T content)把item中的view和相关内容content传进来(content现在还没有用,下一篇将介绍它的用处),进在draglayout中新建用于移动的ImageView。DeleteCellHelper类主要的作用是让CellDragLayout和其它的控件建立联系,充当桥梁的作用。

还需要注意的一点是demo中的underLayout和draglayout在布局中的大小和位置是一样的,因为draglayout分发给underLayout的event是相对于underLayout的,里面包含的位置信息event.getX()和getY()也是相对于dragLayout的,要是underLayout和draglayout在布局中位置不一致需要则经过转换,不然触点在underLayout会表现的不准确。

如果需要转换要怎么写呢?我们可以参考一下ViewGroup中的dispatchTransformedTouchEvent方法,里面有这样一段转换得代码:

           if (child == null || child.hasIdentityMatrix()) {if (child == null) {handled = super.dispatchTouchEvent(event);} else {final float offsetX = mScrollX - child.mLeft;final float offsetY = mScrollY - child.mTop;event.offsetLocation(offsetX, offsetY);handled = child.dispatchTouchEvent(event);event.offsetLocation(-offsetX, -offsetY);}return handled;}

计算完偏移量之后通过event.offsetLocation进行校正,然后在传给子view,最后再更正回来。

好了本篇博客到此结束,下篇分享删除的动画特效。

Android新体会(二)仿桌面实现图标拖动相关推荐

  1. android之 Launcher改造仿桌面排版的效果

     一,背景 1.1 新接手一个灯光控制项目,其页面和效果还是比交复杂的,其中一个功能就是仿苹果桌面来排版灯具,支持拖拽,分组,分页. 拖动图标的时候判断是否空白位置还是已经有占位了,有的话就把两个图标 ...

  2. Android 添加、移除桌面快捷方式图标

    Android 添加.移除和判断 桌面快捷方式图标 思路: Launcher为了应用程序能够定制自己的快捷图标,就注册了一个 BroadcastReceiver 专门接收其他应用程序发来的快捷图标定制 ...

  3. 利用Android 8.0 ShortcutManager创建桌面快捷图标

    创建方法: /**@param context 当前content@param targetClass 快捷图标打开的界面@param backClass 打开后按返回键返回的界面@param sho ...

  4. Android 8.0 华为手机 桌面应用图标显示圆形适配方案

    Android 8.0的启动图标适配方案可以参考以下两篇文章 一篇是郭霖大神的Android应用图标微技巧,8.0系统中应用图标的适配 还有另外一篇:android8.0桌面图标适配以及相应问题的解决 ...

  5. android 开机动画尺寸,手机桌面应用图标和APP启动画面全尺寸

    一.APP启动画面全尺寸 所有图片必须为png格式 如上传iOS AppStore,则必须提供1024px*1024px的图标. 或企业内部分发,则需提供57px*57px和512px*512px的图 ...

  6. Android如何隐藏app的桌面显示图标

    有时候基于一些特殊的需求我们需要将app的桌面图标隐藏,这时该怎么做呢?我们将AndroidManifest.xml中的主activity的 <category android:name=&qu ...

  7. android自定义view(二)-仿华为卡包效果

    前段时间产品经理出了一个卡列表展示效果,效果的大致样子是仿照华为门禁卡卡包效果,研究了一下大致效果出来了,但和华为比还有点差距,主要是动画不是很流畅,仅供大家参考指正,有好的优化方式也可以告诉我,大家 ...

  8. Android动画效果(二) 仿QQ点赞动画

    近日有看到QQ点赞的动画效果,于是模仿写了一个 要实现图中效果,需要用到属性动画,属性动画利用ValueAnimator来跟踪记录对象属性已经变化了多长时间及当前这个时间点的值. 如果不设置的话,动画 ...

  9. android 按home键返回到桌面后,再按桌面应用图标又重新打开该应用的解决方法

    android 按home键返回到桌面后,再按桌面应用图标又重新打开该应用的解决方法 如题. 这个问题困扰了我一下午,查了好多资料都不太跟这个问题沾边,但还是查到了..记录下来,为了自己,也为了方便别 ...

最新文章

  1. python如何创建一个类_python (知识点:类)简单的创建一个类
  2. 记录一次OOM分析过程
  3. Mysql:mysql 控制台程序的提示符 prompt 字符串设置
  4. JsCV Core v0.2发布 Javascript图像处理系列目录
  5. 字典转模型的过程中,空值和id特殊字符的处理
  6. python-kafka 常用 api 汇总
  7. linux free 物理内存,Linux free显示系统内存使用
  8. go语言打印日期_go语言基础:流程控制(4)-多重循环跳转控制
  9. 将XML文件数据插入到数据库中
  10. 用turtle画中国象棋棋盘
  11. 开课吧Java课堂:如何使用isAlive()和join()
  12. 一致性算法中的节点下限(转)
  13. 数据字典模块设计_使用正则表达式采集整站小说数据小说精品屋爬虫模块的设计与实现...
  14. Warning: Binary output can mess up your terminal. Use “--output -“ to tell
  15. 中国土壤厚度空间分布数据
  16. Lync学习资料分享
  17. java excel导入jsp_导入导出EXCEL数据(jsp+ssh)
  18. 鸿蒙车机系统合作,鸿蒙OS车机系统来了!华为吉利合作曝光,博越Pro或率先用上...
  19. 给本地openwrt/LEDE软件源添加软件包,更新Package.sig签名文件,解决Signature check failed问题
  20. 数据驱动业务,说的好听,做好很难!得这样才行

热门文章

  1. 抖音直播间挂人气协议工具
  2. 分享72个商务商城PHP源码,总有一款适合你
  3. 选择器的分类及其优先级
  4. ubuntu 复制文件夹到另一目录命令
  5. Echarts画散点图
  6. App前端,Web前端,后端,微信小程序到底该学啥?
  7. Keras安装+Pycharm配置Keras
  8. 正确简单地安装Tensorflow和Keras
  9. c++读取mnn模型
  10. 什么是Hadoop的HA机制?