引用:http://blog.csdn.net/fzh0803/article/details/6279995

去年做了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定义。

android launcher相关推荐

  1. Android Launcher 分析

    1. Launcher的启动过程 从网络上找了一段关于Launcher的启动过程的文章,作为学习Launcher的背景知识: Linux kernel启动以后会通过app_main进程来初始化andr ...

  2. android辅助功能模拟home键,Android launcher中模拟按home键的实现

    Android launcher中模拟按home键的实现 Intent mHomeIntent = new Intent(Intent.ACTION_MAIN); mHomeIntent.addCat ...

  3. android 模拟点击home,Android launcher中模拟按home键的实现

    Android launcher中模拟按home键的实现 Intent mHomeIntent = new Intent(Intent.ACTION_MAIN); mHomeIntent.addCat ...

  4. android Launcher——ui框架

    着手开发laucher 我个人觉得首先要从ui框架入手,了解清楚了ui框架对laucher就有了一个大致的了解,知道关键的几个类在哪里,对后面进一步深入地研究作出铺垫.废话不多说了,直接进入主题: 1 ...

  5. Android Launcher分析和修改5——HotSeat分析

    今天主要是分析一下Launcher里面的快捷方式导航条--HotSeat,一般我们使用手机底下都会有这个导航条,但是如果4.0的Launcher放到平板电脑里面运行,默认是没有HotSeat的,刚好我 ...

  6. Android Launcher桌面图标显示数字

    之前一直以为是应用本身在对图标进行修改,看了源码之后发现其实主要的工作并不是应用自己完成的,主要的工作在是launcher里面完成的. 关于系统里面类似未读短信的具体处理流程如下: 原理 一个应用要实 ...

  7. android 壁纸改变回调,Android Launcher分析和修改13——实现Launcher编辑模式(1) 壁纸更换...

    已经好久没更新Launcher系列文章,今天不解析源码,讲讲如安在Launcher里面添加桌面设置的功能.今朝很多第三方Launcher或者定制Rom都有简单易用的桌面设置功能.例如小米MIUI的La ...

  8. Android 系列 5.9使用Inkscape创建Android Launcher图标

    5.9使用Inkscape创建Android Launcher图标 问题 您需要Android应用程式的自订启动器图示. 解 Inkscape是一个免费和功能丰富的图形程序,支持导出到位图文件的能力; ...

  9. Android Launcher 界面添加未接来电 / 未读短信条数显示

    原文首发地址 Android Launcher 界面添加未接来电 / 未读短信条数显示 本文代码基于 Android 6.0(高通),原生不支持未接来电以及未读短信的图标右上角数目显示. 涉及到几个文 ...

最新文章

  1. 软件BT是硬盘杀手?
  2. Excel批量导入数据库
  3. 李永乐线性代数2020年强化课手写笔记汇总
  4. ORACLE 外部表的简单使用
  5. Windows传统取证的一些笔记
  6. Fiddler抓取雷电模拟器数据包,模拟器代理设置
  7. JDK安装和环境变量配置(超详细图文)
  8. servlet的九大内置对象和四大作用域
  9. java实现思维导图_Java并发(思维导图)
  10. 2020年十大数字客户体验(CX)软件平台
  11. LeetCode刷题汇总
  12. import.os 文件操作
  13. Excel表格之道 学习笔记(二)
  14. 邮件编码介绍及乱码的解决
  15. css设置图片、边框、背景样式
  16. Centos配置NFS
  17. 计算机专业如何发sci期刊
  18. Ubuntu16.04下firefox flash过期问题
  19. Windows7 个人服务详解及优化
  20. revit插件建模助手的【快速工具箱】功能

热门文章

  1. 组件化 Todo List 编写笔记
  2. 《C++面向对象高效编程(第2版)》——2.29 泛化关系(is-a)
  3. mySQL Slow Query Log Rotation(慢查询日志轮循设置)
  4. 10月10号面试技术总结
  5. [转]PHP用mysql数据库存储session
  6. minicom使用总结
  7. WebService重载问题
  8. Asp.net MVC2.0系列文章-添加操作
  9. 关于eigrp-FSM有限状态机的资料
  10. UBUNTU安装搜狗