目录
前言
Workspace是桌面的主要一个部分,一般设备(如手机)启动起来所看到的桌面的主要界面就是Workspace,在Launcher里其继承关系如下:
Workspace->SmoothPagedView->PagedView->ViewGroup
所以可以说Workspace是一个视图容器类,容器里面主要放插件和应用快捷方式的图标。它负责桌面视图的布局工作,如桌面图标是多少行多少列;用户事件的分发与处理;桌面图标的拖放;子视图的更新等操作。本文简单解析一下Workspace的源码。
初始化
1.布局
1.1.xml布局
其布局在launcher.xml里如下:
<com.android.launcher3.Workspace
android:id="@+id/workspace"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
launcher:defaultScreen="@integer/config_workspaceDefaultScreen" />
然后在Launcher.java的onCreate里调用setupViews初始化变量mWorkspace,以便调用Workspace里的一些方法和变量,初始化如下:
mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
1.2.参数初始化
Workspace的真正Layout是在DeviceProfile.java里。首先在Launcher.java的onCreate里初始化DeviceProfile,然后调用其layout方法实现布局,如下:
.....
DeviceProfile grid = app.initDynamicGrid(this);
.....
grid.layout(this);
先看看DeviceProfile的初始化过程,调用的是LauncherAppState的initDynamicGrid方法,具体如下:
DeviceProfile initDynamicGrid(Context context) {
mDynamicGrid = createDynamicGrid(context, mDynamicGrid);
mDynamicGrid.getDeviceProfile().addCallback(this);
return mDynamicGrid.getDeviceProfile();
}
先调用createDynamicGrid得到mDynamicGrid对象,再通过mDynamicGrid来获取DeviceProfile对象。
LauncherAppState.java里的createDynamicGrid:
static DynamicGrid createDynamicGrid(Context context, DynamicGrid dynamicGrid) {
.....
if (dynamicGrid == null) {
Point smallestSize = new Point();
Point largestSize = new Point();
display.getCurrentSizeRange(smallestSize, largestSize);
dynamicGrid = new DynamicGrid(context,
context.getResources(),
Math.min(smallestSize.x, smallestSize.y),
Math.min(largestSize.x, largestSize.y),
realSize.x, realSize.y,
dm.widthPixels, dm.heightPixels);
}
.....
return dynamicGrid;
}
DynamicGrid.java的构造函数:
public DynamicGrid(Context context, Resources resources,
int minWidthPx, int minHeightPx,
int widthPx, int heightPx,
int awPx, int ahPx) {
DisplayMetrics dm = resources.getDisplayMetrics();
ArrayList<DeviceProfile> deviceProfiles =
new ArrayList<DeviceProfile>();
boolean hasAA = !LauncherAppState.isDisableAllApps();
DEFAULT_ICON_SIZE_PX = pxFromDp(DEFAULT_ICON_SIZE_DP, dm);
// Our phone profiles include the bar sizes in each orientation
deviceProfiles.add(new DeviceProfile("Super Short Stubby",
255, 300, 2, 3, 48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4));
deviceProfiles.add(new DeviceProfile("Shorter Stubby",
255, 400, 3, 3, 48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4));
......
mMinWidth = dpiFromPx(minWidthPx, dm);
mMinHeight = dpiFromPx(minHeightPx, dm);
mProfile = new DeviceProfile(context, deviceProfiles,
mMinWidth, mMinHeight,
widthPx, heightPx,
awPx, ahPx,
resources);
}
可以看到根据不同分辨率加载不同的默认布局文件,最后new DeviceProfile对象。
再看看DeviceProfile的构造函数,上面调用了DeviceProfile的两个构造函数,先看第一个:
DeviceProfile(String n, float w, float h, float r, float c,
float is, float its, float hs, float his, int dlId) {
// Ensure that we have an odd number of hotseat items (since we need to place all apps)
if (!LauncherAppState.isDisableAllApps() && hs % 2 == 0) {
throw new RuntimeException("All Dev