Android4.0 Launcher拖拽原理分析(1)

news/2024/7/7 22:20:44

Android4.0 Launcher拖拽原理分析(一)

Android4.0源码自带的Launcher中,拖拽是由DragController进行控制的。

基本流程是相应的View在检测到用户操作后进行判断,若可以触发拖拽,则设置自身的相应状态,然后将待拖拽对象的Bitmap对象、当前位置、拖拽源、待拖拽对象等信息传给DragControllerstartDrag方法启动拖拽。接下来,DragLayeronInterceptTouchEvent拦截触屏事件,将其转到DragControlleronTouchEvent方法。在DragControlleronTouchEvent中调用DragControllerhandleMoveEvent进行对象的移动,并通知相应拖拽目的对象状态的改变。最后在DragControlleronTouchEvent中检测到抬起事件时调用drop方法释放待拖拽对象,调用endDrag方法结束拖拽。

拖拽开始

Launcher中,拖拽有两种方式触发:1、在Workspace上进行拖拽;2、从AppsCustomizePagedView中选择一个应用或Widget放置到Workspace上。

Workspace上进行拖拽

长按某个图标或Widget

在这种情况下,会调用LauncheronLongClick方法,进而对于非文件夹调用WorkspacestartDrag方法来隐藏相应视图并绘制图标边界(在Workspace上显示的用于标识当前拖拽图标所处位置的蓝色边界图形),最终转到Workspace.beginDragShared方法。


 
 

在打开的文件夹中长按某个图标

Launcher中,对于文件夹中元素的长按,是在FolderonLongClick里处理的,故长按某个图标或Widget中,对于文件夹,则直接返回。

若允许拖拽,则调用WorkspacebeginDragShared进行处理。


 

WorkspacebeginDragShared方法

从上文中可以发现,只要是在Workspace上启动物体的拖拽,最终都会走到Workspace.beginDragShared方法里。在这个方法中,首先会通过createDragBitmap绘制用于拖拽的图形(包括在原图外层绘制一圈红色边界),然后计算位置与边界,并将其传给DragController管理。


 

AppsCustomizePagedView中选择一个应用或Widget放置到Workspace

AppsCustomizePagedView继承自PagedViewWithDraggableItems,即我们平时所说的应用程序抽屉。当长按应用图标或widget时,AppsCustomizePagedView会隐藏,显示Workspace的缩小状态,即SPRING_LOADED

在源码中,该状态转换有三个入口,均在PagedViewWithDraggableItems中给出,即onInterceptTouchEventonTouchEventonLongClick。最终都转到AppsCustomizePagedViewbeginDragging方法。但笔者试了多次,发现只有onLongClick被调用。


 

AppsCustomizePagedViewbeginDragging

beginDragging类似一个代理方法,首先进行Launcher状态的转换,然后会根据被拖拽物的不同,调用不同的拖拽方法。


 
 

应用程序的拖拽beginDraggingApplication

对于应用程序来说,从抽屉拖拽到桌面,界面的隐藏在beginDragging中都已经处理好了,AppsCustomizePagedView不需要保存任何有关被拖拽应用的信息(就算取消拖拽,也只需要重新显示AppsCustomizePagedView就行了,不像Folder那样还需要恢复快捷方式)。因此,只需要通知Workspace绘制图标边界,然后启动拖拽即可。


 

Widget/快捷方式的拖拽beginDraggingWidget

对于Widget列表中的元素,由于有可能为快捷方式,因此还需要进行判断。对不同类型的拖拽物,用不同的方式绘制图形及图标边界。


 

DragController

startDrag开始拖拽

从上文可以发现,无论是以何种方式进入拖拽,最终都是调用DragControllerstartDrag方法进行处理。

DragController中,startDrag是个多态方法,但最终,都走到了以下这个实现中。

public void startDrag(Bitmap b, int dragLayerX, int dragLayerY,
 DragSource source, Object dragInfo, int dragAction,
 Point dragOffset, Rect dragRegion)

startDrag的逻辑比较清晰,主要是通知相应的监听器拖拽开始,然后创建拖拽对象及其视图,将其移动到当前触摸到位置。


 

触屏事件的拦截

onInterceptTouchEvent

DragLayer继承自ViewGroup,其onInterceptTouchEvent方法若返回true,说明需要拦截触屏事件,则后续的一系列事件将传递给自身的onTouchEvent方法,而不再向其子控件传递。

DragControlleronInterceptTouchEventDragLayeronInterceptTouchEvent调用,用于拦截触屏事件的处理。当用户点击屏幕时,触发ACTION_DOWN事件,记录当前触摸位置。当抬起时,触发ACTION_UP事件,结束拖拽。若抬起时处于拖拽中,在当前位置释放被拖拽物(在笔者测试过程中未检测到其调用)。最后,返回是否处于拖拽状态

因此,若此时处于拖拽中,后续的触屏事件将只传递到DragLayeronTouchEvent

onTouchEvent

onTouchEvent由于处理触屏事件,若返回true,则表示消费掉该事件,事件不再向父控件的onTouchEvent传递。

DragControlleronTouchEventDragLayeronTouchEvent调用,用于处理被拖拽物的移动。

startDrag执行完毕,DragController设置拖拽状态为true,这样,触屏事件将最终转到onTouchEvent中,在此处调用handleMoveEvent进行物体的移动。其基本流程如下。


 

handleMoveEvent进行移动

handleMoveEvent是拖拽的主要方法,当用户触发拖拽后,DragController将通过该方法移动被拖拽物视图,并通知各个释放目的对象相应状态的改变。若进入滑屏区域且允许滑屏,执行相应的滑屏操作。如下图所示。


 

drop释放被拖拽物到当前位置

当用户将被拖拽物移动到相应位置后,可以将手指从屏幕上移开。此时,将在onInterceptTouchEvent(未试出)与onTouchEvent中调用drop方法释放被拖拽物。

其主要功能,就是查找拖拽目的对象(DropTarget),若找到且接受释放,通知该对象被拖拽物的放入。最后,通知拖拽源(被拖拽物最初所在的容器)拖拽结果。


 

findDropTarget查找当前位置对应的拖拽目标对象

handleMoveEventdrop中,均使用了findDropTarget来查找当前位置对应的拖拽目的对象,其基本原理就是遍历所有已注册的拖拽目的对象,若其支持放入且当前位置位于该对象的触发区域内,则匹配成功返回该对象。


 

DragController拖拽控制流程总结

总的来说,DragController拖拽控制就是:1、使用startDrag进入拖拽状态;2、使用onInterceptTouchEventonTouchEvent响应用户的触屏动作;3、使用handleMoveEvent处理被拖拽物的移动;4、使用drop将被拖拽物释放到相应位置。


http://www.niftyadmin.cn/n/4606972.html

相关文章

LiMo阶段性成果:又添7款新机器,同时成员扩到50个。

根据LiMo基金会透露,有7款新手机刚刚通过LiMo的认证过程,现在,采用该平台的手机产品再次获得了增加。 通过认证的7款手机分属于摩托罗拉、松下、NEC等等,全部采用最新的LiMo Release 1版本。其中松下和NEC的手机将通过NTT DoCoMo…

摘抄:Java多线程学习

此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢? 本文主要讲java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的线程函数用法、概述…

HTC明确透露Android手机将于第四季出货

这是HTC08的说明简报上的一页:

阿里云-安装jdk

1、阿里云轻量服务器入口 https://swas.console.aliyun.com/?spm5176.2020520001.1011.2.29ff4bd3P4AEDc#/servers 2、使用阿里云的远程连接 3、进入linux命令行界面 3.1 切换超级管理员权限 sudo su root 3.2 建立新的目录 mkdir name #创建新目录rm -rf name #删除目录ls #…

希望Android不是忽悠人,以Google的实力。

在近一段时间内,关于Android 的负面新闻太多:主要是 1 假开源 2 SDK问题太多 3 集成时不顺利,将推迟上市; 我觉得最不好的就是第一条,太忽悠人了。我本人也对目前android的做法不太赞成。不过从另一方面看&#xff…

Myeclipse 反编译工具插件

JadClipse是java的反编译工具,是命令行执行,反编译出来的源文件可读性较高。可惜用起来不太方便。还好 找到myeclipse下的插件,叫JadClipse,安装好之后,只要双击.class文件,就能直接看源文件,包…

ALP应该再开放点!

ALP (ACCESS Linux Platform) 的面太小,目前在日本有些手机推出。 ALP的开发社区ADN, 也是半抱琵琶。很搞笑。 现在的LiMo, Android, symbian, 已经宣称开发了,在Linux Mobilel领域,你这样执著,就像 日系手机在中国市场上溃败…

『高级篇』docker之Mesos微服务部署(26)

原创文章,欢迎转载。转载请注明:转载自IT人故事会,谢谢!原文链接地址:『高级篇』docker之Mesos微服务部署(26) 因本人的mac本才8g,无法同时启动4个虚拟机来完成,3个serve…