转载请注明出处:http://blog.csdn.net/fzh0803/archive/2011/03/26/6279995.aspx

去年做了launcher相关的工作,看了很长时间。很多人都在修改launcher,但还没有详细的文档,把自己积累的东西分享出来,大家一起积累。这份源码是基于2.1的launcher2,以后版本虽有变化,但大概的原理一直还是保留了。

一、主要文件和类

1.Launcher.java:launcher中主要的activity。

2.DragLayer.java:launcher layout的rootview。DragLayer实际上也是一个抽象的界面,用来处理拖动和对事件进行初步处理然后按情况分发下去,角色是一个controller。它首先用onInterceptTouchEvent(MotionEvent)来拦截所有的touch事件,如果是长按item拖动的话不把事件传下去,直接交由onTouchEvent()处理,这样就可以实现item的移动了,如果不是拖动item的话就把事件传到目标view,交有目标view的事件处理函数做相应处理。如过有要对事件的特殊需求的话可以修改onInterceptTouchEvent(MotionEvent)来实现所需要的功能。

3. DragController.java:为Drag定义的一个接口。包含一个接口,两个方法和两个静态常量。接口为DragListener(包含onDragStart(),onDragEnd()两个函数),onDragStart()是在刚开始拖动的时候被调用,onDragEnd()是在拖动完成时被调用。在launcher中典型的应用是DeleteZone,在长按拖动item时调用onDragStart()显示,在拖动结束的时候onDragEnd()隐藏。两个函数包括startDrag()和setDragItemInfo().startDrag()用于在拖动是传递要拖动的item的信息以及拖动的方式,setDragItemInfo()用于传递item的参数信息(包括位置以及大小)。两个常量为DRAG_ACTION_MOVE,DRAG_ACTION_COPY来标识拖动的方式,DRAG_ACTION_MOVE为移动,表示在拖动的时候需要删除原来的item,DRAG_ACTION_COPY为复制型的拖动,表示保留被拖动的item。

4.LauncherModel.java:辅助的文件。里面有许多封装的对数据库的操作。包含几个线程,其中最主要的是ApplicationsLoader和DesktopItemsLoader。ApplicationsLoader在加载所有应用程序时使用,DesktopItemsLoader在加载workspace的时候使用。其他的函数就是对数据库的封装,比如在删除,替换,添加程序的时候做更新数据库和UI的工作。

5.Workspace.java:抽象的桌面。由N个celllaout组成,从cellLayout更高一级的层面上对事件的处理。

6.LauncherProvider.java:launcher的数据库,里面存储了桌面的item的信息。在创建数据库的时候会loadFavorites(db)方法,loadFavorites()会解析xml目录下的default_workspace.xml文件,把其中的内容读出来写到数据库中,这样就做到了桌面的预制。

7.CellLayout.java:组成workspace的view,继承自viewgroup,既是一个dragSource,又是一个dropTarget,可以将它里面的item拖出去,也可以容纳拖动过来的item。在workspace_screen里面定了一些它的view参数。

8.ItemInfo.java:对item的抽象,所有类型item的父类,item包含的属性有id(标识item的id),cellX(在横向位置上的位置,从0开始),cellY(在纵向位置上的位置,从0开始) ,spanX(在横向位置上所占的单位格),spanY(在纵向位置上所占的单位格),screen(在workspace的第几屏,从0开始),itemType(item的类型,有widget,search,application等),container(item所在的)。

9.UserFolder.java: 用户创建的文件夹。可以将item拖进文件夹,单击时打开文件夹,长按文件夹上面标题处可以重命名文件夹。

10.LiveFolder.java:系统自带的文件夹。从系统中创建出的如联系人的文件夹等。

11.DeleteZone:删除框。在平时是出于隐藏状态,在将item长按拖动的时候会显示出来,如果将item拖动到删除框位置时会删除item。DeleteZone实现了DropTarget和DragListener两个接口。

12.LauncherSettings.java:字符串的定义。数据库项的字符串定义,另外在这里定义了container的类型,还有itemType的定义,除此还有一些特殊的widget(如search,clock的定义等)的类型定义。

二、主要模块

1.界面模型:

 
   

Launcher的界面的rootview是DragLayer,它是一个FrameLayout,在它上面workspace(应该说是celllayout)占了绝大部分的空间,celllayout的参数文件是workspace_screen.xml。workspace既是一个DropTarget又是一个DragSource,可以从AllAppGridView中拖出应用程序放在它上面,也可以把它里面的item拖走删除或者拖到bottomabr里面去。

2.Drop& Drag模型:

DragSource:可以拖动的对象来源的容器,在launcher中主要有AllAppGridView,workspace等。

void onDropCompleted(View target, boolean success,int x,int y);

DropTarget:可以放置被拖动的对象的容器。在launcher中有folder,workspace,bottombar等,一个View既可以是Dragsource也可以是DropTarget。主要包含以下几个接口:

boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);

acceptDrop函数用来判断dropTarget是否可以接受item放置在自己里面。

void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);

onDragEnter是item被拖动进入到一个dropTarget的时候的回调。

void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);

onDragOver是item在上一次位置和这一次位置所处的dropTarget相同的时候的回调。

void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);

onDragExit是item被拖出dropTarget时的回调。

boolean onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);

onDrop是item被放置到dropTarget时的回调。

函数的调用模式为:

DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);

if (dropTarget != null) {

/**

* 当这一次的 target 跟上一次相同时,根据坐标来移动item

*/

if (mLastDropTarget == dropTarget) {

dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1],

(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);

else {

/**

* 当上一次的位置跟这一次不同而且上一次的位置不为空,说明item移           *动出了,将上次的 View 根据上次的坐标重新排列,并根据当前坐标重排*当前的*/

if (mLastDropTarget != null) {

mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],

(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);

}

dropTarget.onDragEnter(mDragSource, coordinates[0], coordinates[1],

(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);

}

else {//如果这一次为 null ,上一次不为 null ,那么把上一次坐标位置的 cell 去掉

if (mLastDropTarget != null) {

mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],

(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);

}

}

//记录上次的droptarget

mLastDropTarget = dropTarget;

3.Touch event总结:

由于launcher的事件比较多比较复杂,所以在事件处理的时候一般采用rootview先用onInterceptTouchEvent(MotionEvent)拦截所有的touch事件,经过判断后分发给childview。

判断的规则如下:

a.down事件首先会传递到onInterceptTouchEvent()方法

b.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。

c.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。

d.如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。

e.如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。

三、几种问题的解决方式

1.将所有的应用都排列在桌面上

将所有的应用都排列在桌面是通过首先创建一个三维的boolean型全局数组来记录item的排列情况,第一维是屏数,第二维是纵向上的排列情况,第三维是横向的排列情况,如果那个位置被item所占用就标记为1,否则标记为0.在启动时把全局数组初始化为0,然后在添加的时候把相应的位置置1.凡是涉及到workspace上item的变化,比如移动、添加、删除操作时都需要维护数组,保持数组的正确性,因为在安装新程序时依据数组的状态去判断把item加到什么位置。

2.动态增加屏幕

动态增加屏幕是通过worksapce .addchild(view)的方式实现。基本思路是:首先预先规定所允许的最大的屏幕数,然后在需要增加屏幕而且当前屏幕数没有超过最大屏幕数的时候通过(CellLayout)mInflater.inflate(R.layout.workspace_screen,null)创建一个celllayout实例出来,然后通过addchild把它加入进去。在屏幕上的item被删除时通过从最后一屏起判断屏幕上是否有item,如果有的话保留,没有的话则删除最后一屏,以此类推。

3.预制桌面

         a.添加普通的应用程序快捷方式:

         在../res/xml下的default_workspace.xml文件中加入默认要放置的普通的应用程序。加入的格式为:

<favorite

launcher:packageName="... "    //应用的packageName

launcher:className="... "      //应用启动时的第一个activity

launcher:screen="..."         //放置在第几屏(放在workspace的时候需要,从0开始,0为第一屏,1为第二屏,以此类推...)

launcher:x="..."               //放置x方向的位置(在列中的位置)

launcher:y="..." />           //放置y方向的位置(在行中的位置)

packageName和className可以通过点击程序,然后在打印出的log中找到comp={...},例如如下信息:

comp={com.estrongs.android.taskmanager/com.estrongs.android.taskmanager.TaskManager}。其中com.estrongs.android.taskmanager为packageName, com.estrongs.android.taskmanager.TaskManager为className。

workspace的布局如下:

(0,0)

(1,0)

(2,0)

(3,0)

(4,0)

(0,1)

(1,1)

(2,1)

(3,1)

(4,1)

(0,2)

(1,2)

(2,2)

(3,2)

(4,2)

         b.添加widget:

         在../package/apps/VLauncher/res/xml下的default_workspace.xml文件中加入默认要放置的普通的应用程序。加入的格式为:

<widget

launcher:packageName="..."       //widget的packageName

launcher:className=" ..."       //实现 widget的 receiver 类的名称.

launcher:container="..."        //放置的位置(只能为desktop)

launcher:screen="..."        //放置在第几屏上

launcher:x="..."              //放置的x位置

launcher:y="..."              //放置的y位置

launcher:spanx="..."         //在x方向上所占格数

launcher:spany="..."/>       //在y方向上所占格数

例如,要在第3屏的第一行第二列放置开始放置一个x方向上占两个单位格,y方向上占两个单位格的时钟,可以加入以下代码:

<appwidget

launcher:packageName="com.android.alarmclock"      launcher:className="com.android.alarmclock.AnalogAppWidgetProvider"

launcher:container="desktop"

launcher:screen="2"

launcher:x="1"

launcher:y="0"

launcher:spanx="2"

launcher:spany="2"/>

4.改变主界面的排列方式

         要修改桌面的排列方式,如下,先根据横竖屏设置修改workspace_screen.xml里shortAxisCells和longAxisCells的参数,然后在Launcher.java中修改NUMBER_CELLS_X和NUMBER_CELLS_Y的值,在2.3版本中刚开始往数据库中添加item的时候会去判断,如果不修改NUMBER_CELLS_X和NUMBER_CELLS_Y的话会导致一部分的item显示不出来,导致预制apk的失败。

5.增加worksapce上的屏数

         要增加屏数,首先在根据横竖屏在launcher.xml中的<com.android.launcher.Workspace 中删除或增加 <include android:id="@+id/cellN" layout="@layout/workspace_screen" />,然后在Launcher.java中修改SCREEN_COUNT的值即可。

四、xml文件

       1.workspace_screen.xml

launcher:cellWidth="95dip"

           cell(即item)的宽

launcher:cellHeight="93dip"

           cell(即item)的宽

launcher:longAxisStartPadding="25dip"

较长(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离起点的像素数

launcher:longAxisEndPadding="55dip"

较长(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离终点的像素数

launcher:shortAxisStartPadding="20dip"

较短(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离起点的像素数

launcher:shortAxisEndPadding="120dip"

较短(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离起点的像素数

launcher:shortAxisCells="3"

较短的方向上可以容纳的cell的数量

launcher:longAxisCells="5"

较长的方向上可以容纳的cell的数量

shortAxisCells和longAxisCells决定一个workspace(即CellLayout)上可以容纳的item的个数为shortAxisCells*longAxisCells.

2. application_boxed.xml

       所有应用程序和系统文件夹中item的定义。

3.application.xml

       Workspace的item的layout定义。

转载于:https://www.cnblogs.com/MMLoveMeMM/articles/4204941.html

android_launcher的源码详细分析相关推荐

  1. android_launcher的源码详细分析和壁纸修改 .

    一.主要文件和类 1.Launcher.java:launcher中主要的activity. 2.DragLayer.java:launcher layout的rootview.DragLayer实际 ...

  2. LinkedHashMap 源码详细分析(JDK1.8)

    1. 概述 LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题.除此之外,Linke ...

  3. linkedhashmap 顺序_LinkedHashMap 源码详细分析(JDK1.8)

    1. 概述 LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题.除此之外,Linke ...

  4. FBReader源码详细分析 序言

    2019独角兽企业重金招聘Python工程师标准>>> FBReader源码详细分析 -- 序言 有关FBReader源码的分析,网络上已经有一位叫做"谋哥"的大 ...

  5. android view 源码分析,Android ViewPager源码详细分析

    1.问题 由于Android Framework源码很庞大,所以读源码必须带着问题来读!没有问题,创造问题再来读!否则很容易迷失在无数的方法与属性之中,最后无功而返. 那么,关于ViewPager有什 ...

  6. HashMap 源码详细分析(JDK1.8)

    1. 概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap.HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现.HashMap 允许 null 键和 null 值 ...

  7. vboot源码详细分析-1

    最近一直在研究bootloader之vboot,vboot短小精悍,如果只是用来进行系统的引导,而不要提供其他复杂的功能时候,我认为这是绝佳的上选.这里以MINI2440开发板配套的源码进行分析.这个 ...

  8. DownloadProvider 源码详细分析

    DownloadProvider 简介 DownloadProvider 是Android提供的DownloadManager的增强版,亮点是支持断点下载,提供了"开始下载",&q ...

  9. 一文读懂Spring动态配置多数据源---源码详细分析

    Spring动态多数据源源码分析及解读 一.为什么要研究Spring动态多数据源 代云小说网 https://www.3187.info ​ 期初,最开始的原因是:想将答题服务中发送主观题答题数据给批 ...

最新文章

  1. 你还在认为 count(1) 比 count(*) 效率高?
  2. 老牛:虚拟化让工作如此智慧
  3. LeetCode - Reorder List
  4. 计算数值二进制表达式中1的个数
  5. 更改span标签样式_CSS 内嵌样式
  6. mysql入参映射_Mybatis中的Mapper映射Sql中传参类型(如Bean,基本类型,List...)与取值的方式 与foreach的几种用法!!...
  7. 一次sendmsg的改造过程
  8. 最新PHP云购源码+带机器人/控制/教程/去授权说明
  9. 更改以太网共享属性家庭网络连接值,解决电脑笔记本连接校园网显示无internet无法开热点或开热点手机无ip分配问题
  10. light动名词_动名词ing的用法
  11. 12个开源的后台端管理系统
  12. 如何防止U盘病毒入侵方法
  13. Openstack 发行版本列表
  14. Shopee通知:未通过实名认证将导致订单无法正常出运
  15. css如何去掉或修改浏览器默认滚动条
  16. 连接Apple ID服务器时出错
  17. c语言编程 企业发放,求c语言编程企业员工全年销售额统计及奖金发放系..._统计师_帮考网...
  18. python 社区-谈谈Python社区7种治理方案
  19. Python爬虫之Js逆向案例(6)-某道翻译
  20. 解决微信H5页面软键盘弹起后页面下方留白的问题(iOS端)

热门文章

  1. jquery点击缩略图切换视频播放的视频切换焦点图效果
  2. IE6下绝对定位的高度自适应
  3. VS.NET 2005真是太好用了!
  4. android 自定义paint,Android中自定义常用的三个对象解析(Paint,Color,Canvas)
  5. 函数 单片机glint_GL 库函数
  6. javascript字典中添加数组_如何在JavaScript中使用数组方法:Mutator方法
  7. mysql性能调优与架构设计 51cto_MySQL 数据库性能优化之表结构优化
  8. redis服务的部署
  9. 问题 I: 成对最小公倍数(数学)
  10. MySQL数据库InnoDB坏页处理修复