思考: 接上一篇,在Launcher初始化默认桌面widget
的时候,需要选择默认defaultLayoutId
,接下来需要弄清楚,默认layout是怎么来的。
前面分析过,defaultLayoutId
来自InvariantDeviceProfile
的初始化过程
InvariantDeviceProfile.java
private InvariantDeviceProfile(Context context) {
String gridName = getCurrentGridName(context);
String newGridName = initGrid(context, gridName);
...
}
private String initGrid(Context context, String gridName) {
DefaultDisplay.Info displayInfo = DefaultDisplay.INSTANCE.get(context).getInfo();
ArrayList<DisplayOption> allOptions = getPredefinedDeviceProfiles(context, gridName);
DisplayOption displayOption = invDistWeightedInterpolate(displayInfo, allOptions);
initGrid(context, displayInfo, displayOption);
return displayOption.grid.name;
}
---
private void initGrid(
Context context, DefaultDisplay.Info displayInfo, DisplayOption displayOption) {
GridOption closestProfile = displayOption.grid;
numRows = closestProfile.numRows;
numColumns = closestProfile.numColumns;
numHotseatIcons = closestProfile.numHotseatIcons;
dbFile = closestProfile.dbFile;
defaultLayoutId = closestProfile.defaultLayoutId;
...
}
先getPredefinedDeviceProfiles
获取系统所有的DisplayOption
,然后invDistWeightedInterpolate
根据系统的尺寸,匹配最接近的DisplayOption
。
在getPredefinedDeviceProfiles
的过程中,加载的是R.xml.device_profiles
<grid-option
launcher:name="4_by_4"
launcher:numRows="5"
launcher:numColumns="4"
launcher:numFolderRows="4"
launcher:numFolderColumns="4"
launcher:numHotseatIcons="4"
launcher:dbFile="launcher_4_by_4.db"
launcher:defaultLayoutId="@xml/default_workspace_4x4" >
<display-option
launcher:name="Short Stubby"
launcher:minWidthDps="275"
launcher:minHeightDps="420"
launcher:iconImageSize="48"
launcher:iconTextSize="13.0"
launcher:canBeDefault="true" />
...
其中定义了好多grid-option
,每个grid-option
内部包含几个display-option
包含桌面显示多少行,多少列,数据库名称,默认布局id,最大最小宽高,图标大小这些属性,
接下来就是匹配最佳的过程
DisplayOption displayOption = invDistWeightedInterpolate(displayInfo, allOptions);
---
@VisibleForTesting
static DisplayOption invDistWeightedInterpolate(
DefaultDisplay.Info displayInfo, ArrayList<DisplayOption> points) {
Point smallestSize = new Point(displayInfo.smallestSize);
Point largestSize = new Point(displayInfo.largestSize);
float width = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y),
displayInfo.metrics);
float height = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y),
displayInfo.metrics);
Collections.sort(points, (a, b) ->
Float.compare(dist(width, height, a.minWidthDps, a.minHeightDps),
dist(width, height, b.minWidthDps, b.minHeightDps)));
GridOption closestOption = points.get(0).grid;
float weights = 0;
DisplayOption p = points.get(0);
if (dist(width, height, p.minWidthDps, p.minHeightDps) == 0) {
return p;
}
DisplayOption out = new DisplayOption(closestOption);
for (int i = 0; i < points.size() && i < KNEARESTNEIGHBOR; ++i) {
p = points.get(i);
float w = weight(width, height, p.minWidthDps, p.minHeightDps, WEIGHT_POWER);
weights += w;
out.add(new DisplayOption().add(p).multiply(w));
}
return out.multiply(1.0f / weights);
}
这里传入的参数,第一个是系统当前显示信息,包含了宽高等属性,我们当前系统的显示屏宽高为600*1024,
根据系统宽高,使用数学公式,计算平方根,根据平方根大小对集合排序。
Collections.sort(points, (a, b) ->
Float.compare(dist(width, height, a.minWidthDps, a.minHeightDps),
dist(width, height, b.minWidthDps, b.minHeightDps)));
private static float dist(float x0, float y0, float x1, float y1) {
return (float) Math.hypot(x1 - x0, y1 - y0);
}
排完序,还不是直接取最接近的值,而是对集合里前三名进行权重计算,使iconsize
,iconTextSize
属性取最适合的值。