Android Launcher 3 简单分析

Posted 屌丝迷途

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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.

 

以上是关于Android Launcher 3 简单分析的主要内容,如果未能解决你的问题,请参考以下文章

Android launcher3 -- launcher3源码1

android launcher 之踩到的坑

Android 4.0 Launcher2源码分析——启动过程分析

Android 源码分析 Launcher 桌面程序启动分析

Android 源码分析 Launcher 启动

android launcher 之踩到的坑