launcher 修改--launcher 架构解析


launcher 修改--launcher 架构解析 要想做好 launcher,对其基本的架构了解是必须的,在这篇文章里,简单的介绍 下 launcher 中类的构成和架构,首先,这篇文章中很多资源均从互联网中获得, 感谢网友们的无私奉献,大家都共享,进步才会更快。 第一步,先看两张从网上找来的 launcher 的架构图。 第二张: 通过这两张图,简单的说下: 整个 launcher,准确来说应该是 homescreen 更为合适,是一个包含三个 child view 的 FrameLayout(com.android.launcher.DragLayer)。 第一个 child 就是桌面 com.android.launcher.Workspace。这个桌面又包含 5 个 child。每个 child 就对应一个桌 面。这就是你在 Android 上看到的五个桌 面。每个桌面上可以放置下列对象:应用快捷方式,appwidget 和 folder。(第 一张图应该是以前版 本的,在 2.2 以前的版本应该是只有三个桌面,在 2.3 中, 有五个桌面) 第二个 child 是一个 SlidingDrawer 控件,这个控件由两个子控件组成。一个是 com.android.launcher.HandleView,就是 Android 桌面下方的把手,当点击这 个把手时,另一个子控 件,com.android.launcher.AllAppsGridView 就会弹出, 这个子控件列出系统中当前安装的所有类型为 category.launcher 的 Activity。 第三个 child 是 com.android.launcher.DeleteZone。当用户在桌面上长按一个 widget 时,把手位置就会出现一个垃圾 桶形状的控件,就是这个控件。(其实 在 2.2 以后的版本中,在左下方和右下方添加了页面标记,来告诉用户当前在哪 个桌面,其代码在 launcher.xml 代码中, 源码打印? 1. 13. 14. 下面就是 launcher 中主要类的简介: AddAdapter:添加桌面元素的适配器, 维护了 live fold , widget , shortcut , wallpaper 4 个 ListItem , 长按桌面会显示该列表 AllAppsGridView:Icon 列表的的主界面,继承 gridView。 ApplicationInfo:一个可启动的应用。 ApplicationsAdapter:gridview 的 adapter。 BubbleTextView:一个定制了的 textview,主要用于显示应用图标。 DeleteZone:luancher 的删除区域,继承 ImageView。在平时是出于隐藏状态, 在将 item 长按拖动的时候会显示出来,如果将 item 拖动到删除框位置时会删 除 item。 DeleteZone 实现了 DropTarget 和 DragListener 两个接口。 DragController:拖动控制接口。为 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。 DragLayer:整个 launcher 的父节点,继承 FrameLayout,实现接口 DrayController,是内部支持拖拽的 viewgroup。DragLayer 实际上也是一个抽 象的界面,用来处理拖动和对事件进行初步处理然后按情况分发下去,角色是一 个 controller。它 首先用 onInterceptTouchEvent(MotionEvent)来拦截所有的 touch 事件,如果是长按 item 拖动的话不把事件传下去, 直接交由 onTouchEvent()处理,这样就可以实现 item 的移动了,如果不是拖动 item 的话 就把事件传到目标 view,交有目标 view 的事 件处理函数做相应处理。如过有 要对事件的特殊需求的话可以修改 onInterceptTouchEvent(MotionEvent)来实 现所需要的功能。 DragSource:拖动源接口,定义了 void onDropCompleted(View target, boolean success)。 DropTarget:拖动目标,定义很多拖动过程需要的方法:onDrop,onDragEnter, onDragOver,onDragExit,acceptDrop。 FastBitmapDrawable:工具 Folder:Icons 的集合 FolderIcon:出现在 workspace 的 icon 代表了一个 folder FolderInfo: ItemInfo 子类 HandleView:launcher 抽屉的开关,不过在 android2.2 已经没用抽屉了。 InstallShortcutReceiver,UninstallShortcutReceiver:一个 broadcastrecier ItemInfo:代表 Launcher 中一个 Item(例如 folder)对 item 的抽象,所有类型 item 的父类,item 包含的属性有 id(标识 item 的 id),cellX(在横向位置上 的位置,从 0 开始),cellY(在纵向位置上的位置,从 0 开始) ,spanX(在 横 向位置上所占的单位格),spanY(在纵向位置上所占的单位格),screen(在 workspace 的第几屏,从 0 开 始),itemType(item 的类型,有 widget,search, application 等),container(item 所在的)。 Launcher:整个 launcher 的程序的入口,代码量最大的一个文件。 LauncherApplication:在 VM 中设置参数 LauncherAppWidgetHost,LauncherAppWidgetHostView,:Widget 相关 LauncherModel: MVC 中的 M,里面有许多封装的对数据库的操作。 包含几个线 程,其中最主要的是 ApplicationsLoader 和 DesktopItemsLoader。 ApplicationsLoader 在加 载所有应用程序时使用,DesktopItemsLoader 在加载 workspace 的时候使用。其他的函数就是对数据库的封装,比如在删除,替换, 添 加程序的时候做更新数据库和 UI 的工作。 LauncherProvider:launcher 的数据库, 一个 contentprovider 里面存储了桌 面的 item 的信息。在创建数据库的时候会 loadFavorites(db)方 法, loadFavorites()会解析 xml 目录下的 default_workspace.xml 文件,把其中的 内容读出来写到数据库中,这样就做到 了桌面的预制。 LauncherSettings:设置相关的工具,数据库项的字符串定义,另外在这里定义 了 container 的类型,还有 itemType 的定义,除此还有一些特殊的 widget(如 search,clock 的定义等)的类型定义。 LiveFolder,LiveFolderAdapter,LiveFolderIcon,LiveFolderInfo: livefolder 相关 Search: 搜索 UserFolder,UserFolderInfo:文件夹包含 applications,shortcuts Utilities:小工具 WallpaperChooser:选择 wallpaper 的 activity Workspace:整个界面 layout,几个窗口就是他下面的子节点。 widget : 代表启动的 widget 实例,例如搜索 在桌面中,有一下四种类型的对象: 1. ITEM_SHORTCUT,应用快捷方式,对应实现布局文件 R.layout.application 2. ITEM_APPWIDGET,app widget 桌面组件 3. ITEM_LIVE_FOLDER,文件夹 --UserFolderInfo 对应实现布局文件 R.layout.folder_icon --LiveFolderInfo 对应实现布局文件 R.layout.live_folder_icon 4. ITEM_WALLPAPER,墙纸。 下面,我们详细的来说一下 launcher 里面的详细功能: 1.DragLayer--DragLayer 继承 FrameLayout,并在此基础上组合了 DragController 实现拖放功能,DragLayer 主要监听下面两个用户事件 onInterceptTouchEvent 和 onTouchEvent 并交给 DragController 进行处理,DragController 根据是否在拖放中等信息控 制控件拖放过程处理。DragLayer 是 Launcher 这个 activity 的顶层 view,其 实在 Launcher2 这个应用只有 Laucher.java 这么一个 activity。 2.DeleteZone-- 源码打印? 1. 在 launcher.xml 中,可以发现,DeleteZone 默认是不显示的 android:visibility="invisible",但 是我们每次开始拖放图标的时候 DeleteZone 就显示了,这个功能是如何实现的呢?在代码中可以发现 DeleteZone 实现了 DragController.DragListener 接口, 1. public class DeleteZone extends ImageView implements Drop Target, DragController.DragListener DragListener 提供两个接口方法, onDragStart:隐藏把手,显示 DeleteZone onDragEnd:显示把手,隐藏 DeleteZone 在 DeleteZone 中,看一下代码: 1. public void onDragStart(DragSource source, Object info, i nt dragAction) { 2. final ItemInfo item = (ItemInfo) info; 3. if (item != null) { 4. mTrashMode = true; 5. createAnimations(); 6. final int[] location = mLocation; 7. getLocationOnScreen(location); 8. mRegion.set(location[0], location[1], location[0] + mRight - mLeft, 9. location[1] + mBottom - mTop); 10. mDragController.setDeleteRegion(mRegion ); 11. mTransition.resetTransition(); 12. startAnimation(mInAnimation); 13. mHandle.startAnimation(mHandleOutAnimat ion); 14. setVisibility(VISIBLE); 15. } 16. } 17. 18. public void onDragEnd() { 19. if (mTrashMode) { 20. mTrashMode = false; 21. mDragController.setDeleteRegion(null); 22. startAnimation(mOutAnimation); 23. mHandle.startAnimation(mHandleInAnimati on); 24. setVisibility(GONE); 25. } 26. } 分别在开始 DragController 开始拖放和结束拖放的时候被调用. 另外 DeleteZone 实现了 DropTarget 接口的 onDrop 方法 public void onDrop(DragSource source, int x, int y, int xOff set, int yOffset, 1. DragView dragView, Object dragInfo) { 2. final ItemInfo item = (ItemInfo) dragInfo; 3. 4. if (item.container == -1) return; 5. 6. if (item.container == LauncherSettings.Favor ites.CONTAINER_DESKTOP) { 7. if (item instanceof LauncherAppWidge tInfo) { 8. mLauncher.removeAppWidget((Laun cherAppWidgetInfo) item); 9. } 10. } else { 11. if (source instanceof UserFolder) { 12. final UserFolder userFolder = (UserFolder) source; 13. final UserFolderInfo userFold erInfo = (UserFolderInfo) userFolder.getInfo(); 14. // Item must be a Shortcut Info otherwise it couldn't have been in the folder 15. // in the first place. 16. userFolderInfo.remove((Shortcut Info)item); 17. } 18. } 19. if (item instanceof UserFolderInfo) { 20. final UserFolderInfo userFolderInfo = (UserFolderInfo)item; 21. LauncherModel.deleteUserFolderContentsF romDatabase(mLauncher, userFolderInfo); 22. mLauncher.removeFolder(userFolderInfo); 23. } else if (item instanceof LauncherAppWidg etInfo) { 24. final LauncherAppWidgetInfo launcherA ppWidgetInfo = (LauncherAppWidgetInfo) item; 25. final LauncherAppWidgetHost appWidget Host = mLauncher.getAppWidgetHost(); 26. if (appWidgetHost != null) { 27. final int appWidgetId = lau ncherAppWidgetInfo.appWidgetId; 28. // Deleting an app widget ID is a void call but writes to disk before returning 29. // to the caller... 30. new Thread("deleteAppWidgetId" ) { 31. public void run() { 32. appWidgetHost.d eleteAppWidgetId(launcherAppWidgetInfo.appWidgetId); 33. } 34. }.start(); 35. } 36. } 37. LauncherModel.deleteItemFromDatabase(mLauncher, item); 38. } 当把图标拖放到 DeleteZone,就会调用 DeleteZone,实现的 onDrop 方法对应用 图标进行删除处理。 3.屏幕左右移动按钮,就是使用的 ImageView, 1. 13. 14. 注意三点, --1.桌面左右移动时 Drawable 的变换,变换图标列表可查看 home_arrows_right.xml ,ImageView 通过把 drawable 传递给 worksapce,当桌面切换时通过调用 Drawable.setLevel()方法实现不同图标显示。 --2.当点击实现左右桌面切换,查看上面的布局文件中 android:onClick="previousScreen",该属性定义了一个 onClick 事件响应函 数,在 Launcher.java 中的 788 行。 1. @SuppressWarnings({"UnusedDeclaration"}) 2. publicvoid previousScreen(View v) { 3. if(!isAllAppsVisible()) { 4. mWorkspace.scrollLeft(); 5. } 6. } --3.在(Launcher.setupViews)中添加了长按事件 OnLongClickListener 有当长 按会执行 launcher.onlongclick 方法,方法执行显示 5 个桌面的预览微缩图显 示。 4.RelativeLayout--android:id="@+id/all_apps_button_cluster",如前面截 图右边灰色竖状条,它是一个相对布局对象,上面承载了三个 view 中间是一个 HandleView,是一个进入 allappview 的按钮,HandleView 的左面是 拨号,右面是浏览器两个 ImageView。 --HandleView --1.点击事件 传递给 Launcher.onClick 进 行处理 显示应用菜单 view --2.长按事件 传递给 Launcher.onLongClick 进行处理,方法执行显示 5 个桌面的预览微缩图显示 --拨号或者浏览器 --onClick 响应: android:onClick="launchHotSeat" 5.Workspace--用户桌面包括 5 个 workspace_screen,launcher:defaultScreen="2"在前面已经说过,表示默认桌 面是第三个。 workspace 继承了 viewgroup,5 个 workspace_screen 作为它的 child,值得注意 它只接收 CellLayout 类型的 child,workspace 重写了 addview 函数,添加了非 CellLayout 的 child 将抛异常 --Workspace 长按事件由 launcher.onLongClick 来监听 --Workspace 实现了 DropTarget, DragSource 两个接口,意味着 Workspace 既 是拖放源,又是拖放目的地 --Workspace 实现 DragScroller 接口,DragScroller 接口提供两个方法 void scrollLeft()和 void scrollRight()在拖放过程被 DragController 调用实现桌面的左右滚动。 --CellLayout Workspace 下的一个桌面布局,CellLayout 也是 ViewGroup 的子类, Workspace 下有 5 个 CellLayout 顺序排列,Workspace 下布局文件: android:scrollbars="horizontal"决定了 5 个 CellLayout 排列是横向还是纵向 的 1. 当纵向的控件不够 cells 排列时,cell 将产生重叠,横向不产生重叠,横向每 个 cell 间隔至少为 0 --CellLayout 覆盖重新实现了 onMeasure 方法,和 onlayout 方法,它限定 了 child view 使用的布局参数类型为 CellLayout.LayoutParams 因此企图通过 修改 workspace_screen.xml 来改变它的桌面布局是不会得以成功 的,你必须修改 CellLayout 类 --CellLayout.LayoutParams 说明,CellLayout.LayoutParams 下有几个成员需要说明一下 --cellX:该 child view 占用的第几列的 cell(若横向占用多个 cell,表示最左边的 cellx) --cellY: 该 child view 占用的第几行的 cell(若纵向占用多个 cell,表示最上边的 celly) --cellHSpan:横向跨越的列数 --cellVSpan: 纵向跨越行数 --isDragging:该 child 是否正在被拖动 --regenerateId:是否重新生成 view id 最后以网上淘来的 launcher 类的关系来结束这篇文章:
还剩11页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 6 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

DavikChen

贡献于2012-10-12

下载需要 6 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf