Android拖拽详解
Android中实现拖拽其实很简单,系统早已经提供了api让我使用,主要用到了View的startDrag(startDragAndDrop API24+)
方法以及OnDragListener
。
startDrag
先来看下方法介绍:
/*** Starts a drag and drop operation. When your application calls this method, it passes a* {@link android.view.View.DragShadowBuilder} object to the system. The* system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)}* to get metrics for the drag shadow, and then calls the object's* {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself.* <p>* Once the system has the drag shadow, it begins the drag and drop operation by sending* drag events to all the View objects in your application that are currently visible. It does* this either by calling the View object's drag listener (an implementation of* {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the* View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method.* Both are passed a {@link android.view.DragEvent} object that has a* {@link android.view.DragEvent#getAction()} value of* {@link android.view.DragEvent#ACTION_DRAG_STARTED}.* </p>* <p>* Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object,* int) startDragAndDrop()} on any attached View object. The View object does not need to be* the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related* to the View the user selected for dragging.* </p>* @param data A {@link android.content.ClipData} object pointing to the data to be* transferred by the drag and drop operation.* @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the* drag shadow.* @param myLocalState An {@link java.lang.Object} containing local data about the drag and* drop operation. When dispatching drag events to views in the same activity this object* will be available through {@link android.view.DragEvent#getLocalState()}. Views in other* activities will not have access to this data ({@link android.view.DragEvent#getLocalState()}* will return null).* <p>* myLocalState is a lightweight mechanism for the sending information from the dragged View* to the target Views. For example, it can contain flags that differentiate between a* a copy operation and a move operation.* </p>* @param flags Flags that control the drag and drop operation. This can be set to 0 for no* flags, or any combination of the following:* <ul>* <li>{@link #DRAG_FLAG_GLOBAL}</li>* <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li>* <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li>* <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li>* <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li>* <li>{@link #DRAG_FLAG_OPAQUE}</li>* </ul>* @return {@code true} if the method completes successfully, or* {@code false} if it fails anywhere. Returning {@code false} means the system was unable to* do a drag, and so no drag operation is in progress.*/public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder,Object myLocalState, int flags)
复制代码
看到英文就头大?没事,我来翻译解释一下。
启动拖放操作。当应用程序调用此方法时,它将传递一个DragShadowBuilder对象到系统。系统调用此对象的onProvideShadowMetrics(Point, Point)方法获取拖动阴影的参数指标,然后调用onDrawShadow(Canvas)来绘制阴影。一旦系统有了拖动阴影,它就开始拖拽操作,通过将拖拽事件发送到当前可见的应用程序中的所有视图对象。这些视图可以通过设置OnDragListener在或者实现onDragEvent方法接受DragEvent(事件)来响应和拖拽事件。
可以看到有四个参数:
ClipData data
其实就是一个封装数据的对象,通过拖放操作传递给接受者。该对象可以存放一个Item的集合,Item可以存放如下数据:
public static class Item {final CharSequence mText;final String mHtmlText;final Intent mIntent;Uri mUri;
}
复制代码
注意到可以存放Intent,因此,通常可以将参数存入intent,然后通过静态方法直接创建ClipData对象:
ClipData clipData = ClipData.newIntent("label", intent);
复制代码
该数据可以在监听的中的DragEvent获取
ClipData clipData = event.getClipData();
复制代码
简单点说就是可以将一些数据传递给拖拽的接受者,该拖拽其实可以跨Activity的,如果只是同一个Activity可以使用第三个参数传递数据。
DragShadowBuilder shadowBuilder
用于创建拖拽view是的阴影,也就是跟随手指移动的视图,通常直接使用默认即可生成与一个原始view相同,带有透明度的阴影:
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
复制代码
Object myLocalState
当你的拖拽行为是在同一个Activity中进行时可以传递一个任意对象,在监听中可以通过{@link android.view.DragEvent#getLocalState()}获得。如果是跨Activity拖拽中无法访问此数据,getLocalState()
将返回null。
int flags
控制拖放操作的标志。因为没有标志可以设置为0,flag标志拖动是否可以跨越窗口以及一些访问权限(需要API24+)。
了解了方法参数含义,接下来就是启用拖拽了,通常会通过长按来触发拖拽:
iv.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);v.startDrag(null, shadowBuilder, null, 0);//震动反馈v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);return true;}});
复制代码
开始拖拽后还要有来接受这些拖拽事件,这就需要OnDragListener了。
OnDragListener
OnDragListener是在View中定义的接口,用于响应拖拽事件,可以通过View的setOnDragListener
方法设置监听,有点类似于点击事件。
public interface OnDragListener { boolean onDrag(View v, DragEvent event);
}
复制代码
设置监听,实现onDrag(View v, DragEvent event)
方法,其中View是设置该监听的view,DragEvent是拖拽事件,可以通过event.getAction()
获取具体事件类型,这和TouchEvent非常类似,具体事件类型有如下几种:
fl_blue.setOnDragListener(new View.OnDragListener() {@Overridepublic boolean onDrag(View v, DragEvent event) {//v 永远是设置该监听的view,这里即fl_blueString simpleName = v.getClass().getSimpleName();Log.w(BLUE, "view name:" + simpleName);//获取事件int action = event.getAction();switch (action) {case DragEvent.ACTION_DRAG_STARTED:Log.i(BLUE, "开始拖拽");break;case DragEvent.ACTION_DRAG_ENDED:Log.i(BLUE, "结束拖拽");break;case DragEvent.ACTION_DRAG_ENTERED:Log.i(BLUE, "拖拽的view进入监听的view时");break;case DragEvent.ACTION_DRAG_EXITED:Log.i(BLUE, "拖拽的view离开监听的view时");break;case DragEvent.ACTION_DRAG_LOCATION:float x = event.getX();float y = event.getY();long l = SystemClock.currentThreadTimeMillis();Log.i(BLUE, "拖拽的view在监听view中的位置:x =" + x + ",y=" + y);break;case DragEvent.ACTION_DROP:Log.i(BLUE, "释放拖拽的view");break;}//是否响应拖拽事件,true响应,返回false只能接受到ACTION_DRAG_STARTED事件,后续事件不会收到return true;}});
复制代码
此处通过event.getX(); event.getY();
获取的x,y是手指(也即是被拖拽view的中心点)在监听view的位置。
释放手指会触发ACTION_DRAG_ENDED
事件,如果此时被拖拽的view正好在监听的view中,则会先触发ACTION_DROP
事件。
可以同时有多个view设置拖拽监听接受事件,我给红色和蓝色view都设置了OnDragListener,然后拖动Android图片到蓝色区域后释放,可以看到日志如下:
03-09 14:53:54.518 12937-12937/com.huburt.app.androiddrag I/RED: 开始拖拽
03-09 14:53:54.518 12937-12937/com.huburt.app.androiddrag I/BLUE: 开始拖拽
03-09 14:53:55.689 12937-12937/com.huburt.app.androiddrag I/BLUE: 拖拽的view进入监听的view时
03-09 14:53:55.689 12937-12937/com.huburt.app.androiddrag I/BLUE: 拖拽的view在BLUE中的位置:x =111.0,y=2.0
03-09 14:53:55.870 12937-12937/com.huburt.app.androiddrag I/BLUE: 拖拽的view在BLUE中的位置:x =112.0,y=23.0
03-09 14:53:56.014 12937-12937/com.huburt.app.androiddrag I/BLUE: 释放拖拽的view
03-09 14:53:56.017 12937-12937/com.huburt.app.androiddrag I/RED: 结束拖拽
03-09 14:53:56.017 12937-12937/com.huburt.app.androiddrag I/BLUE: 结束拖拽
复制代码
现在我们已经可以把Android图片拖出来,但是还不能把它放入目标view,其实也挺简单的,只需要在ACTION_DROP事件做一些处理即可:
case DragEvent.ACTION_DROP:Log.i(BLUE, "释放拖拽的view");ImageView localState = (ImageView) event.getLocalState();FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);layoutParams.topMargin = (int) event.getY() - localState.getWidth() / 2;layoutParams.leftMargin = (int) event.getX() - localState.getHeight() / 2;((ViewGroup) localState.getParent()).removeView(localState);fl_blue.addView(localState, layoutParams);break;
复制代码
这里因为是在同一个Activity中,我是将拖拽的view直接传递过来了,当然也可以只传递图片,然后在接收的view中重新new一个imageview现实图片。
运行一下就可以看到view可以拖拽到目标位置了。
可能文字描述不是特别清楚,请看demo
Android拖拽详解相关推荐
- react-draggable实现拖拽详解
react-draggable 属性 常用属性 属性列表 事件列表 举例 首先安装 react-draggable 实现移动 希望小编写的能够帮助到你
- 《Android游戏开发详解》——第1章,第1.6节函数(在Java中称为“方法”更好)...
本节书摘来自异步社区<Android游戏开发详解>一书中的第1章,第1.6节函数(在Java中称为"方法"更好),作者 [美]Jonathan S. Harbour,更 ...
- JMessage Android 端开发详解
JMessage Android 端开发详解 目前越来越多的应用会需要集成即时通讯功能,这里就为大家详细讲一下如何通过集成 JMessage 来为你的 App 增加即时通讯功能. 首先,一个最基础的 ...
- 《Java和Android开发实战详解》——2.5节良好的Java程序代码编写风格
本节书摘来自异步社区<Java和Android开发实战详解>一书中的第2章,第2.5节良好的Java程序代码编写风格,作者 陈会安,更多章节内容可以访问云栖社区"异步社区&quo ...
- Android事件流程详解
Android事件流程详解 网络上有不少博客讲述了android的事件分发机制和处理流程机制,但是看过千遍,总还是觉得有些迷迷糊糊,因此特地抽出一天事件来亲测下,向像我一样的广大入门程序员详细讲述an ...
- Android Studio 插件开发详解二:工具类
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78112856 本文出自[赵彦军的博客] 在插件开发过程中,我们按照开发一个正式的项 ...
- 《Android游戏开发详解》一2.16 区分类和对象
本节书摘来异步社区<Android游戏开发详解>一书中的第2章,第2.16节,作者: [美]Jonathan S. Harbour 译者: 李强 责编: 陈冀康,更多章节内容可以访问云栖社 ...
- Android Framework系统服务详解
Android Framework系统服务详解 操作环境 系统:Linux (Ubuntu 12.04) 平台:高通 Android版本:5.1 PS: 符号...为省略N条代码 一.大致原理分析 A ...
- android屏幕适配详解
android屏幕适配详解 官方地址:http://developer.android.com/guide/practices/screens_support.html 一.关于布局适配建议 1.不要 ...
最新文章
- RDS for MySQL 5.7 备份恢复为本地实例
- struts2静态方法和动态方法调用
- vs2005常用调试快捷键 (转载)
- 恶补sql知识(一)
- [Android]对MVC和MVP的总结
- zImage内核镜像解压过程详解
- UVa 10118 免费糖果(记忆化搜索+哈希)
- linux ssh升级回退,Linux-SSH升级及回退方案
- java继承案例分析,Java day5【第十四章】继承案例分析
- 主控芯片测试软件,主控芯片检测工具MyDiskTest的使用教程的详解【图文】
- ArcGIS学习笔记-1.功能-1.1裁剪
- zmq Pub-Sub 模式
- TSC2004 电阻式触摸屏控制器驱动问题
- 计算机语言收入排名,全球人均收入排名美元_计算机语言收入排名
- 【NLP】huggingface阶段性学习小结
- 微信 考勤 php,JavaScript_微信企业号开发之微信考勤Cookies的使用,在上篇文章给大家介绍了微信 - phpStudy...
- 谁说NTFS不支持UEFI启动的?启动U盘放不了超过4G的文件怎么办?Server2016 Win10 U盘UEFI启动制作方法
- 齐岳提供的双核金属铱配合物黏度探针C10((df-ppy)2Ir(bpy)(CH2)10(bpy)Ir(btph)22+)-
- fork后父子进程共享资源
- 网页中嵌入电视直播代码
热门文章
- DPDK使用linux drivers(二十九)
- 2 模版_轻量html模版渲染库 cJinja
- axios vue 回调函数_Vue 02 —— Vue 入门小案例~使用 Axios 中的GET、POST请求
- 微软职位内部推荐-Senior Software Engineer_Azure
- [ORACLE错误]oracle 不能更新 PL/SQL 点击“edit data”报“ these query results are not updateable”...
- 一起谈.NET技术,Visual Studio 2010 中的代码约定设置
- 在虚拟主机中无法实现缩放等交互
- 怎么挪动_你真的懂iPhone上的小圆点怎么玩吗
- impala连接使用方法
- asp.net ajax控件工具集 AutoCompleteExtender控件