一、计算桌面布局参数
📄 common/src/main/ets/default/viewmodel/LayoutViewModel.tscalculateDesktop(): any {Log.showInfo(TAG, 'calculateDesktop start');/*** 01. 计算桌面布局参数*//*** 获取桌面布局的边距值 mMargin,用于计算实际的可用宽度*/let margin = this.mLauncherLayoutStyleConfig.mMargin;/*** 根据屏幕宽度 mScreenWidth 和边距计算实际可用的宽度 realWidth,边距在两侧都有,所以要乘以 2*/let realWidth = this.mScreenWidth - 2 * margin;/*** 计算实际可用高度 realHeight* 工作区高度 mWorkSpaceHeight 减去指示器高度 mIndicatorHeight 和系统顶部高度 mSysUITopHeight*/let realHeight = this.mWorkSpaceHeight - this.mIndicatorHeight - this.mSysUITopHeight;/*** 检查导航栏状态 mNavigationBarStatus* 如果导航栏存在,则从 realHeight 中减去系统底部高度 mSysBottomHeight*/if (this.mNavigationBarStatus) {realHeight = realHeight - this.mLauncherLayoutStyleConfig.mSysBottomHeight;}...}
1.1 边距
let margin = this.mLauncherLayoutStyleConfig.mMargin;
这里的 this.mLauncherLayoutStyleConfig 是 LauncherLayoutStyleConfig 类,它有两个子类:
- 如果你的设备是 Phone 类型,那么就会从 PhoneLauncherLayoutStyleConfig 里面去取 mMargin 值:
📄 product/phone/src/main/ets/common/PhoneLauncherLayoutStyleConfig.tsmMargin = PhonePresetStyleConstants.DEFAULT_LAYOUT_MARGIN;
进而读取 PhonePresetStyleConstants 里面默认配置的 DEFAULT_LAYOUT_MARGIN 值:
📄 product/phone/src/main/ets/common/constants/PhonePresetStyleConstants.tsstatic readonly DEFAULT_LAYOUT_MARGIN = 12;
- 如果你的设备是 Pad 类型,那么就会从 PadLauncherLayoutStyleConfig 里面去取 mMargin 值:
📄 product/pad/src/main/ets/common/PadLauncherLayoutStyleConfig.tsmMargin = PadPresetStyleConstants.DEFAULT_LAYOUT_MARGIN;
进而读取 PadPresetStyleConstants 里面默认配置的 DEFAULT_LAYOUT_MARGIN 值:
📄 product/phone/src/main/ets/common/constants/PhonePresetStyleConstants.tsstatic readonly DEFAULT_LAYOUT_MARGIN = 82;
1.2 可用宽度
let realWidth = this.mScreenWidth - 2 * margin;
我们来看看 mScreenWidth(屏幕宽度)是从哪里来的:
📄 common/src/main/ets/default/viewmodel/LayoutViewModel.tsinitScreen(navigationBarStatus?: string): void {this.mScreenWidth = AppStorage.get('screenWidth');this.mScreenHeight = AppStorage.get('screenHeight');...
}
通过 AppStorage.get() 获取的,那肯定有地方 AppStorage.setOrCreate() 了。
- 如果设备是 Phone 类型
📄 product/phone/src/main/ets/pages/EntryView.etsaboutToAppear(): void {Log.showInfo(TAG, 'aboutToAppear');...this.getWindowSize();...
}private getWindowSize(): void {try {this.screenWidth = px2vp(windowManager.getWindowWidth());this.screenHeight = px2vp(windowManager.getWindowHeight());AppStorage.setOrCreate('screenWidth', this.screenWidth);AppStorage.setOrCreate('screenHeight', this.screenHeight);} catch (error) {Log.showError(TAG, `getWindowWidth or getWindowHeight error: ${error}`);}
}
- 如果设备是 Pad 类型
📄 product/pad/src/main/ets/pages/EntryView.etsaboutToAppear(): void {Log.showInfo(TAG, 'aboutToAppear');...this.getWindowSize();...
}private getWindowSize(): void {try {this.screenWidth = px2vp(windowManager.getWindowWidth());this.screenHeight = px2vp(windowManager.getWindowHeight());AppStorage.setOrCreate('screenWidth', this.screenWidth);AppStorage.setOrCreate('screenHeight', this.screenHeight);} catch (error) {Log.showError(TAG, `getWindowWidth or getWindowHeight error: ${error}`);}
}
可以发现,逻辑一摸一样。
我们带着看下 windowManager.getWindowWidth() 里面的逻辑:
📄 common/src/main/ets/default/manager/WindowManager.tsgetWindowWidth(): number {if (this.mDisplayData == null) {this.mDisplayData = this.getWindowDisplayData();}// 获取显示设备的屏幕宽度return this.mDisplayData?.width as number;
}private getWindowDisplayData(): display.Display | null {let displayData: display.Display | null = null;try {// @ohos.display ==> 获取当前默认的 display 对象displayData = display.getDefaultDisplaySync();} catch(err) {Log.showError(TAG, `display.getDefaultDisplaySync error: ${JSON.stringify(err)}`);}return displayData;
}
我现在手上的设备是 Pad,打个 Log 看看:
com.ohos.launcher I @@@ pepsimaxin : 屏幕宽度 ==> this.mScreenWidth = 1280
二、计算列数、行数及间距
接下来我们继续分析第 2 部分代码:
📄 common/src/main/ets/default/viewmodel/LayoutViewModel.tscalculateDesktop(): any {Log.showInfo(TAG, 'calculateDesktop start');/*** 01. 计算桌面布局参数*/---------------------------------------------------/*** 02. 计算列数、行数及间距*//*** 获取每个应用图标的尺寸 mAppItemSize*/let itemSize = this.mLauncherLayoutStyleConfig.mAppItemSize;/*** 获取最小网格间距 mGridGutter*/let minGutter = this.mLauncherLayoutStyleConfig.mGridGutter;/*** 计算可以容纳多少列图标:~~ 是双重按位取反操作符,用于快速向下取整*/let column = ~~((realWidth + minGutter) / (itemSize + minGutter));/*** 计算列之间剩余的宽度 userWidth*/let userWidth = (realWidth + minGutter - (itemSize + minGutter) * column);/*** 重新计算列间距 gutter*/let gutter = (userWidth / (column - 1)) + minGutter;/*** 类似列的计算,计算可以容纳多少行图标*/let row = ~~((realHeight + gutter) / (itemSize + gutter));/*** 计算顶部边距 marginTop,用于使图标在垂直方向上居中*/let marginTop = ((realHeight + gutter - (itemSize + gutter) * row) / 2);...}
2.1 应用图标大小
let itemSize = this.mLauncherLayoutStyleConfig.mAppItemSize;
又碰到 LauncherLayoutStyleConfig 了,那么图标尺寸肯定不同设备配置不一样了:
// Phone
mAppItemSize = PhonePresetStyleConstants.DEFAULT_APP_LAYOUT_SIZE;
static readonly DEFAULT_APP_LAYOUT_SIZE = 80;// Pad
mAppItemSize = PadPresetStyleConstants.DEFAULT_APP_LAYOUT_SIZE;
static readonly DEFAULT_APP_LAYOUT_SIZE = 96;
2.2 最小网格间距
let minGutter = this.mLauncherLayoutStyleConfig.mGridGutter;
同理,我们直接看配置信息:
// Phone
mGridGutter = PhonePresetStyleConstants.DEFAULT_APP_LAYOUT_MIN_GUTTER;
static readonly DEFAULT_APP_LAYOUT_MIN_GUTTER = 5;// Pad
mGridGutter = PadPresetStyleConstants.DEFAULT_APP_LAYOUT_MIN_GUTTER;
static readonly DEFAULT_APP_LAYOUT_MIN_GUTTER = 6;
2.3 图标列数
// 计算容纳多少列图标
let column = ~~((realWidth + minGutter) / (itemSize + minGutter));
例如我手里的平板,我们打个 Log 看下数据:
pid-1360 I @@@ pepsimaxin : 桌面布局边距 ==> margin = 82
pid-1360 I @@@ pepsimaxin : 屏幕宽度 ==> this.mScreenWidth = 1280
com.ohos.launcher D @@@ pepsimaxin : realWidth = 1116, minGutter = 6, itemSize = 96
com.ohos.launcher D @@@ pepsimaxin : column = 11
看下平板效果: