Android Launcher 3 简单分析

最近在学习Android Launcher的相关知识,在github上找到可以在Android studio上编译的Launcher 3代码,地址:https://github.com/rydanliu/Launcher3

Launcher 3的界面主要由SearchDropTargetBar、Workspace、CellLayout、PageIndicator、Hotseat组成。如下图:

Launcher 3 最主要的是一个Activity,基本上所有操作都集中在这个Activity上。这个Activity文件为Launcher.java,他的布局文件为launcher.xml。

下面为竖屏的布局文件,路径为res/layout-port/launcher.xml。

 1 <?xml version="1.0" encoding="utf-8"?>
 2
 3 <!-- Full screen view projects under the status bar and contains the background -->
 4 <com.android.launcher3.LauncherRootView xmlns:android="http://schemas.android.com/apk/res/android"
 5     xmlns:launcher="http://schemas.android.com/apk/res-auto"
 6     android:id="@+id/launcher"
 7     android:layout_width="match_parent"
 8     android:layout_height="match_parent"
 9     android:fitsSystemWindows="true">
10
11     <com.android.launcher3.DragLayer
12         android:id="@+id/drag_layer"
13
14         android:layout_width="match_parent"
15         android:layout_height="match_parent">
16
17         <com.android.launcher3.FocusIndicatorView
18             android:id="@+id/focus_indicator"
19             android:layout_width="22dp"
20             android:layout_height="22dp" />
21
22         <!-- The workspace contains 5 screens of cells -->
23         <!-- DO NOT CHANGE THE ID -->
24         <com.android.launcher3.Workspace
25             android:id="@+id/workspace"
26             android:layout_width="match_parent"
27             android:layout_height="match_parent"
28             launcher:defaultScreen="@integer/config_workspaceDefaultScreen"
29             launcher:pageIndicator="@+id/page_indicator"></com.android.launcher3.Workspace>
30
31         <!-- DO NOT CHANGE THE ID -->
32         <include
33             android:id="@+id/hotseat"
34             layout="@layout/hotseat"
35
36             android:layout_width="match_parent"
37             android:layout_height="match_parent" />
38
39         <include
40             android:id="@+id/overview_panel"
41             layout="@layout/overview_panel"
42             android:visibility="gone" />
43
44         <!-- Keep these behind the workspace so that they are not visible when
45              we go into AllApps -->
46         <include
47             android:id="@+id/page_indicator"
48             layout="@layout/page_indicator"
49             android:layout_width="wrap_content"
50             android:layout_height="wrap_content"
51             android:layout_gravity="center_horizontal" />
52
53         <include
54             android:id="@+id/search_drop_target_bar"
55
56             layout="@layout/search_drop_target_bar" />
57
58         <include
59             android:id="@+id/widgets_view"
60             layout="@layout/widgets_view"
61             android:layout_width="match_parent"
62             android:layout_height="match_parent"
63             android:visibility="invisible" />
64
65         <include
66             android:id="@+id/apps_view"
67             layout="@layout/all_apps"
68             android:layout_width="match_parent"
69             android:layout_height="match_parent"
70             android:visibility="invisible" />
71     </com.android.launcher3.DragLayer>
72
73     <ViewStub
74         android:id="@+id/launcher_overlay_stub"
75         android:layout_width="match_parent"
76         android:layout_height="match_parent"
77         android:inflatedId="@+id/launcher_overlay"
78         android:layout="@layout/launcher_overlay" />
79 </com.android.launcher3.LauncherRootView>

SearchDropTargetBar

屏幕最上方有个搜索框,在我们拖动图标的时候,搜索框会替换成“删除“

Workspace

就是屏幕上左右滑的好几屏幕的容器

CellLayout

Workspace里面可以滑动的单独一屏,CellLayout负责图标和小部件的显示和整齐摆放。

PageIndicator

滑动屏幕的时候看见下方的指示器

Hotseat

用来放置比较常用的应用,比如拨号,短信,相机等。

下面介绍几个类

CellLayout 

mCountX 和 mCountY   分别表示 “x方向icon的个数” 和 “y方向icon的个数”

mOccupied 二维数组用来标记每个cell是否被占用,内部类CellInfo为静态类,其对象用于存储cell的基本信息。

DeviceProfile 类

设置各元素布局的padding  。修改workspace的padding使用getWorkspacePadding方法。

 1     /** Returns the workspace padding in the specified orientation */
 2     Rect getWorkspacePadding(boolean isLayoutRtl) {
 3         Rect searchBarBounds = getSearchBarBounds(isLayoutRtl);
 4         Rect padding = new Rect();
 5         if (isLandscape && transposeLayoutWithOrientation) {
 6             // Pad the left and right of the workspace with search/hotseat bar sizes
 7             if (isLayoutRtl) {
 8                 padding.set(hotseatBarHeightPx, edgeMarginPx,
 9                         searchBarBounds.width(), edgeMarginPx);
10             } else {
11                 padding.set(searchBarBounds.width(), edgeMarginPx,
12                         hotseatBarHeightPx, edgeMarginPx);
13             }
14         } else {
15             if (isTablet) {
16                 // Pad the left and right of the workspace to ensure consistent spacing
17                 // between all icons
18                 float gapScale = 1f + (dragViewScale - 1f) / 2f;
19                 int width = getCurrentWidth();
20                 int height = getCurrentHeight();
21                 int paddingTop = searchBarBounds.bottom;
22                 int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx;
23                 int availableWidth = Math.max(0, width - (int) ((inv.numColumns * cellWidthPx) +
24                         (inv.numColumns * gapScale * cellWidthPx)));
25                 int availableHeight = Math.max(0, height - paddingTop - paddingBottom
26                         - (int) (2 * inv.numRows * cellHeightPx));
27                 padding.set(availableWidth / 2, paddingTop + availableHeight / 2,
28                         availableWidth / 2, paddingBottom + availableHeight / 2);
29             } else {
30                 // Pad the top and bottom of the workspace with search/hotseat bar sizes
31
32                 padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
33                         searchBarBounds.bottom,
34                         desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
35                         hotseatBarHeightPx + pageIndicatorHeightPx);
36
37
38             }
39         }
40         return padding;
41     }

比如我要将workspace里图标顶部不留空隙,需要设置padding.set的第二个参数为0.

1 padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
2                         0,//searchBarBounds.bottom,
3                         desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
4                         hotseatBarHeightPx + pageIndicatorHeightPx);

InvariantDeviceProfile类

一些不变的设备相关参数管理类,landscapeProfile 和 portraitProfile为横竖屏模式的DeviceProfile。

getPredefinedDeviceProfiles方法 负责加载在不同设备上不同的布局,和图标大小等。

 1 ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles() {
 2         ArrayList<InvariantDeviceProfile> predefinedDeviceProfiles = new ArrayList<>();
 3         // width, height, #rows, #columns, #folder rows, #folder columns,
 4         // iconSize, iconTextSize, #hotseat, #hotseatIconSize, defaultLayoutId.
 5         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Super Short Stubby",
 6                 255, 300,     2, 3, 2, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
 7         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Shorter Stubby",
 8                 255, 400,     3, 3, 3, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
 9         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Short Stubby",
10                 275, 420,     3, 4, 3, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
11         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Stubby",
12                 255, 450,     3, 4, 3, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
13         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus S",
14                 296, 491.33f, 4, 4, 4, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
15         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 4",
16                 335, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
17
18
19
20         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 5",
21                 359, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
22         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Large Phone",
23                 406, 694,     5, 5, 4, 4, 4, 64, 14.4f,  5, 56, R.xml.default_workspace_5x5));
24         // The tablet profile is odd in that the landscape orientation
25         // also includes the nav bar on the side
26         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 7",
27                 575, 904,     5, 6, 4, 5, 4, 72, 14.4f,  7, 60, R.xml.default_workspace_5x6));
28         // Larger tablet profiles always have system bars on the top & bottom
29         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 10",
30                 727, 1207,    5, 6, 4, 5, 4, 76, 14.4f,  7, 64, R.xml.default_workspace_5x6));
31         predefinedDeviceProfiles.add(new InvariantDeviceProfile("20-inch Tablet",
32                 1527, 2527,   7, 7, 6, 6, 4, 100, 20,  7, 72, R.xml.default_workspace_4x4));
33         return predefinedDeviceProfiles;
34     }

比如我在上面代码的17行加入下列代码,将Hotseat设置成3格,图标大小为72dp

1         predefinedDeviceProfiles.add(new InvariantDeviceProfile("MX 4",
2                 359, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 3, 72, R.xml.default_workspace_4x4));

由于launcher是有许多自定义控件构成的,这里涉及到onMesure,onLayout,onDraw方法的复写

onMesure方法顾名思义,主要是用来重新测量自定义控件的高度和宽度,就是设置它的dimesion,一般所有自定义VIEW都需要复写这个方法。

onLayout则主要是ViewGroup需要复写这个方法,其作用给这个ViewGroup下子View布局好显示的位置。

onDraw则是需要真真正正画出内容的控件需要复写的方法,比如textview,或者其子类,其最终利用一个很重要的类Canvas的对象来实现一系列的画图,比如canvas.drawcircle,canvas.drawline.

时间: 2024-10-12 19:49:55

Android Launcher 3 简单分析的相关文章

Android.mk文件简单分析

Android.mk文件简单分析 一个Android.mk文件用来向编译系统描述需要编译的源代码.具体来说:该文件是GNUMakefile的一小部分,会被编译系统解析一次或多次.可以在每一个Android.mk中定义一个或多个模块,也可以在几个模块中使用同一个源代码文件. 每个模块属下列类型之一: 1)APK程序,一般的Android程序,编译打包生成apk文件 2)JAVA库,java类库,编译打包生成jar文件 3)  C\C++应用程序,可执行的C\C++应用程序 4)C\C++静态库,编

Android ListView初始化简单分析

下面是分析ListView初始化的源码流程分析,主要是ListVIew.onLayout过程与普通视图的layout过程完全不同,避免流程交代不清楚,以下是一个流程的思维导图. 思维导图是顺序是从左向右,从上向下. 一. 先看构造函数,上图中1.1就不分析了,主要是读取一些ListView参数,直接来看1.2 ViewGroup构造函数源码 private void initViewGroup() { ...... // 初始化保存当前ViewGroup中所有View的数组 mChildren

Android应用程序启动过程——Launcher源码分析

当我们在Launcher界面单击一个应用程序图标时就会启动一个程序,那这一个过程究竟发生了些哪样呢?让我们跟踪Launcher源码来分析一下吧. 先上流程图: step1.追踪Launcher  从源码中我们可以发现Launcher其实也是一个程序,它继承于Activity.找到该文件中的onCreate()方法,代码片段如下: protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceSta

通过Android录音进行简单音频分析

Android录音有MediaRecorder和AudioRecord两种方式,前者使用方便,可以直接生成录音文件,但是录音格式为aac和amr等等,都经过压缩处理,不方便进行音频分析. 而用AudioRecord可以得到PCM编码的原音频数据,可以用FFT对数据进行处理,简单分析声音的频率. 1.AndroidRecord录音 private static final String FILE_NAME = "MainMicRecord"; private static final i

Android Launcher分析和修改2——Icon修改、界面布局调整、壁纸设置

上一篇文章说了如何修改Android自带Launcher2的默认界面设置(http://www.cnblogs.com/mythou/p/3153880.html). 今天主要是说说Launcher里面图标.布局.壁纸等的设置问题.毕竟我们一般修改Launcher,这些都是需要修改的地方,也是比较容易修改的部分.按照效果图(效果图在上一篇文章),分开说明如何修改,以及里面涉及的逻辑分析. 原创博文,转载请标明出处:http://www.cnblogs.com/mythou/p/3155692.h

Android开源项目pulltorefresh分析与简单使用

在Android开发中有时我们需要访问网络实时刷新数据,比如QQ好友在线状态最新信息,QQ空间需要显示更多的好友动态信息,EOE论坛客户端显示更多的文章帖子信息等.android-pulltorefresh开源项目提供一个向下滑动即刷新列表的功能,将该项目稍作修改即可应用到自己的项目中. 1.下载地址 https://github.com/johannilsson/android-pulltorefresh 该项目为 Android 应用提供一个向下滑动即刷新列表的功能. 2.工程组成 Pull

Android属性动画AnimatorSet源码简单分析

跟上之前的两篇文章 Android属性动画ValueAnimator源码简单分析 Android属性动画ObjectAnimator源码简单分析 继续看AnimatorSet源码的大概过程. AnimatorSet 提供了一种把多个动画放到一起,按照某种特定的顺序来播放,比如一个接一个的播放或者多个动画一起播放. AnimatorSet简单使用随便举一个最简单的例子 //AnimatorSet AnimatorSet animSet = new AnimatorSet(); ObjectAnim

Android 4.0 Launcher源码分析系列(一)

从今天起傻蛋打算做一个系列文章,对最新的Android 4.0 系统中的Launcher,也就是Android 4.0原生的桌面程序,进行一个深入浅出的分析,从而引领Android系统的编程爱好者对 Launcher的设计思想,实现方式来做一个研究,从而能够通过这个实例最掌握到目前世界领先的设计方法,同时在程序中加入我们的一些新的实现.众所周知,对一些优秀源代码的分析,是提高编程水平的一条便捷的方式,希望本系列文章能够给大家带来一定的启发,同时欢迎大家和作者一起讨论,作者的微博是:http://

Android.mk简单分析

LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := Settings LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) # Use the folloing include to m