Android Launcher3 基本功能分析

1, 界面的布局, 从上往下分别为:DeleteDropTarget(应用卸载区域,它是一个DropTarget)

Workspace(页面容器,一个页面是一个CellLayout)

PageIndicator(指示器,指示workspace当前位于第几个页面)

Hotseat(底部图标区域)

2,Launcher 桌面图标的加载:

LauncherApplication:onCreate()创建 IconCache 和 LauncherModel, 并为 LauncherModel 设置广播过滤条件, 如应用安装广播, 配置切换广播等 ;

Launcher:onCreate()创建 DragController,LauncherAppWidgetHost, 用 setupViews()初始化各个 view ;

LauncherModel:startLoader() 开启 LoaderTask 线程, 用于加载桌面图标 ;

LauncherModel:loadAndBindWorkspace()分为 loadWorkspace 和 bindWorkspace 两个过程, 如果是刚刷完机或恢复出厂设置, loadWorkspace 会解析相应的 xml 文件, 从中读取 workspace 和 hotseat 的图标配置, 插入到新创建的 launcher.db 数据库中, 并形成相应的数据结构: sBgWorkspaceItems,sBgAppWidgets,sBgFolders. 如果已经存在了 launcher.db 文件, 则直接查询 launcher.db, 加载相应的数据结构. 而 bindWorkspace, 顾名思义, 是进行桌面图标的绑定, 也就是根据 loadWorkspace 生成的数据结构来创建并显示图标的过程, 它会依次调用 Launcher 的 bindItems(),bindFolders,bindAppWidgets, 先显示当前页面, 再显示其他页面.

3, 数据结构 (data) 和视图 (view) 的对应关系:

桌面应用: shortcutInfo 对应 BubbleTextView

所有应用: AppInfo 对应 BubbleTextView

桌面小部件: LauncherAppWidgetInfo 对应 LauncherAppWidgetHostView

文件夹: FolderInfo 对应 FoldeIcon

4, 图标的拖拽:

谈拖拽, 首先要谈 2 个概念, DragSource 和 DropTarget.DragSource 是拖拽源所在的容器, DropTarget 则为拖拽目的地所处的容器.

DragSource:Workspace,Folder 和 AppcustomizedPagedView. 注意, Hotseat 逻辑上应当也属于 DragSource, 只是我们的代码中把它归并 Workspace 中去处理了.

DropTarget:Workspace,Folder,DeleteDropTarget.Workspace 中图标的拖拽, 是从 Launcher 的 onLongClick 开始的, Folder 则从它自己的 onLongClick 开始.

以 Workspace 中的图标拖拽为例, 流程如下:Launcher:onLongClick->

Workspace:startDrag->Workspace:createDragOutline->

Workspace:beginDragShared->

DragController:startDrag->DragController:handleMoveEvent

上面是图标长按, 触发的一系列函数调用, 如果此时, 再滑动呢, 根据下面的函数

DragController 的 onTouchEvent 中caseMotionEvent.ACTION_MOVE:

handleMoveEvent(dragLayerX,dragLayerY);

break;

可知, 滑动时会不断触发 handleMoveEvent, 这样就能看到图标跟着手移动了.

那么跟手移动的虚图标是在哪里绘制的呢, 前面说到了 DragSource 和 DropTarget, 在你拖动图标到放手的过程中, 会依次调用 DragController.DragListener 的 onDragStart,

DropTarget 的 onDragEnter,onDragOver,onDragExit,onDrop,

DragSource 的 onDropCompleted,

最后会调用 DragController.DragListener 的 onDragEnd.

应用虚图标的绘制是放在 Workspace 的 onDragOver 中:if(!nearestDropOccupied&&!isWidgetOverView&&(mAuroraSwapTag||!mFromDesktopTag)){

mDragTargetLayout.visualizeDropLocation(child,mDragOutline,

(int)mDragViewVisualCenter[0],(int)mDragViewVisualCenter[1],

mTargetCell[0],mTargetCell[1],item.spanX,item.spanY,false,

d.dragView.getDragVisualizeOffset(),d.dragView.getDragRegion());

}

滑动时, Workspace 的 onDragOver 会跟着手不断被执行, 根据计算出来的最近的位置, 来放置 mDragOutline. 被拖拽图标的隐藏和显示分别在 startDrag 和 onDropCompleted 中处理的. 比较特殊的是, 当滑动到 Workspace 的边界的时候, 边界位置会显示条状的蓝色竖线, 然后决定页面是否跳转, 代码如下, 这也是在 DragController 的 handleMoveEvent 中if(x

if(mScrollState==SCROLL_OUTSIDE_ZONE){

mScrollState=SCROLL_WAITING_IN_ZONE;

if(mDragScroller.onEnterScrollArea(x,y,SCROLL_LEFT)){

mLauncher.getDragLayer().onEnterScrollArea(SCROLL_LEFT);

mScrollRunnable.setDirection(SCROLL_LEFT);

mHandler.postDelayed(mScrollRunnable,delay);

}

}

}elseif(x>mScrollView.getWidth()-mScrollZone&&y

if(mScrollState==SCROLL_OUTSIDE_ZONE){

mScrollState=SCROLL_WAITING_IN_ZONE;

if(mDragScroller.onEnterScrollArea(x,y,SCROLL_RIGHT)){

mLauncher.getDragLayer().onEnterScrollArea(SCROLL_RIGHT);

mScrollRunnable.setDirection(SCROLL_RIGHT);

mHandler.postDelayed(mScrollRunnable,delay);

}

}

}else{

clearScrollRunnable();

}

}

如果不是长按事件, 只是滑动页面, 则 DragLayer 的 OnInterceptTouchEvent 会返回 false, 把事件传递给 Workspace 去处理.

5, 图标推挤:

在 Workspace.java 的 onDragOver 方法里边处理的if(!nearestDropOccupied){// 有空位, 不需要推挤图标, 直接放置

mDragTargetLayout.visualizeDropLocation(child,mDragOutline,

(int)mDragViewVisualCenter[0],(int)mDragViewVisualCenter[1],

mTargetCell[0],mTargetCell[1],item.spanX,item.spanY,false,

d.dragView.getDragVisualizeOffset(),d.dragView.getDragRegion());

}elseif((mDragMode==DRAG_MODE_NONE||mDragMode==DRAG_MODE_REORDER)

&&!mReorderAlarm.alarmPending()&&(mLastReorderX!=reorderX||

mLastReorderY!=reorderY)){

int[]resultSpan=newint[2];

mDragTargetLayout.performReorder((int)mDragViewVisualCenter[0],

(int)mDragViewVisualCenter[1],minSpanX,minSpanY,item.spanX,item.spanY,

child,mTargetCell,resultSpan,CellLayout.MODE_SHOW_REORDER_HINT);

// Otherwise, if we aren't adding to or creating a folder and there's no pending

// reorder, then we schedule a reorder

ReorderAlarmListenerlistener=newReorderAlarmListener(mDragViewVisualCenter,

minSpanX,minSpanY,item.spanX,item.spanY,d.dragView,child);

mReorderAlarm.setOnAlarmListener(listener);

mReorderAlarm.setAlarm(REORDER_TIMEOUT);

}

如果当前将要放置的位置已经被占据了, 则除了计算出需要移动的图标外, 还设置了一个延时器 ReorderAlarm, 这个延时器本质上是一个通过 Handler.postDelayed 的 Runnable. 设置延时的目的, 是为了给创建文件夹提供缓冲时间, 如果在这个延时时间内, 被拖拽的图标与将要放至的位置上的图标的中心距离足够近, 就会触发新文件夹的创建, 此时会取消 ReorderAlarm. 如果延时的时间到了, 而距离没有达到, 则会直接触发 ReorderAlarm, 播放图标挪动的动画.

6, 总结:

LauncherModel.java 是整个 Launcher 中最重要的一个类, 它保存有整个 Launcher 所需的全部数据结构, 可以理解为 Model 层. Launcher.java 则负责 UI 的显示, 所有图标的创建和显示都需要放到它里边去处理, 可以理解为 View 层. DragController 则实现了对拖拽事件的拦截和对滑动事件的分发, 可以理解为 Control 层. 这是基本的架构, 其他的业务需求是在此基础上, 进行搭建的.

来源: http://www.jianshu.com/p/92ed054cf87c

android launcher3,Android Launcher3 基本功能分析相关推荐

  1. android 时钟动态图标,Android 8.1 Launcher3实现动态指针时钟功能

    本文主要实现功能,可能有不合理的地方 首先创建一个实现功能的工具里,直接上代码: import android.content.Context; import android.graphics.Bit ...

  2. Android 9/10 Launcher3 适配出现的问题修改

    Android 10 将桌面设置图标长按出现的弹框中的电池去掉,去掉后如图: 这个主要是关于Android新功能Shortcuts的运用. Launcher3的流程: 在packages\apps\L ...

  3. Android动态秒针插件app,Android 8.1 Launcher3实现动态指针时钟功能

    本文主要实现功能,可能有不合理的地方 首先创建一个实现功能的工具里,直接上代码: import android.content.Context; import android.graphics.Bit ...

  4. android app启动流程分析,Android应用开发之Android 7.0 Launcher3的启动和加载流程分析...

    本文将带你了解Android应用开发Android 7.0 Launcher3的启动和加载流程分析,希望本文对大家学Android有所帮助. Android 7.0 Launcher3的启动和加载流程 ...

  5. Android 7.0 Launcher3的启动和加载流程分析----转载

     Android 7.0 Launcher3的启动和加载流程分析,Launcher的本质就是一个普通应用,它比普通应用多配置了Category的Android:name="android ...

  6. Android 7.0 Launcher3的启动和加载流程分析

    本文的分析基于MTK提供的Android 7.0源码,并非Google官方提供的源码,其中可能有一些小的差异,还望谅解. Launcher的本质就是一个普通应用,它比普通应用多配置了Category的 ...

  7. Android:通过systrace进行性能分析及使用-详细

    Android:通过systrace进行性能分析 https://www.cnblogs.com/blogs-of-lxl/p/10926824.html 一.Systrace 简介 Systrace ...

  8. 【Android】Android源码版本

    学而不思则罔,思而不学则殆 [Android]Android源码版本 1.下载manifest.git 2.checkout到不同的分支 3.源码下载地址列表 4.Android源码存在的分支 1.下 ...

  9. Android 7.1.2(Android N) Android系统启动流程

    Android 7.1.2(Android N) Android系统启动流程 源码: system/core/rootdir/ init.rc init.zygote64.rc system/core ...

最新文章

  1. fabric-ca-server 配置mysql数据库,区块链(4)
  2. 本工作簿不能再使用其他新字体_1.2.16 EXCEL篇之关于工作表的操作合集
  3. 【大会】QoE也能驱动业务创新
  4. Java:使用Toxiproxy模拟各种连接问题
  5. 【转】刨根究底字符编码之三——字符编码的由来
  6. 《高性能MySQL》 第1章 MySQL架构与历史
  7. 二阶等差数列的性质及应用
  8. matlab2c使用c++实现matlab函数系列教程-abs函数
  9. matlab 子函数句柄,matlab-函数句柄程序.ppt
  10. 北斗导航 | 两个地面站之间的多跳卫星通信链路(附matlab代码)
  11. CHB-MIT波士顿儿童医院癫痫EEG脑电数据处理(一)
  12. [Codeforces Round #428 DIV2E (CF839E)] Mother of Dragons
  13. 基于证书的反垃圾邮件系统
  14. AR开发有哪些AR库,AR SDK
  15. Bootstrap3动态添加的元素tooltip不生效
  16. GetElementByName
  17. 关于MIT6.828_HW9_barriers xv6 homework9的一些问题
  18. mysql高级 tigger触发器 --[2]
  19. 技术人员如何判断靠谱的创业合伙人?
  20. PLSql连接Oracle时提示TNS:无监听程序的解决方法

热门文章

  1. 揭秘美国云计算 大企业是第一推动力
  2. Office 2003 sp3(CVE-2012-0158)漏洞分析报告
  3. 那些年,Android音视频开发那些事儿
  4. python实现哈夫曼树的可视化
  5. 快手2020校园招聘秋招笔试--工程C试卷 (编程题题解全)
  6. layui table 表格设置透明
  7. C# 编写Windows Service(windows服务程序)(第二种)
  8. 基于贝叶斯分类器的社区UGC反垃圾模型
  9. 【Stephen Boyd】应用线性代数导论课件
  10. 计算机专业不会打字怎么办,科目一考试电脑怎么用?科目一不会打字怎么办