往期推文全新看点(文中附带全新鸿蒙5.0全栈学习笔录)
✏️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?
✏️ 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~
✏️ 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?
✏️ 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?
✏️ 记录一场鸿蒙开发岗位面试经历~
✏️ 持续更新中……
概述
平板和PC/2in1设备作为常用的移动端设备,在日常生活中发挥着重要作用,也是HarmonyOS 1+8设备全场景一体化体验中不可或缺的一环。为了在平板和PC/2in1设备上开发出体验更好的应用,建议先熟悉设备的独有特性。
设备特性主要包含以下几点:
- 相较于手机设备,平板和PC/2in1设备拥有较高分辨率的大屏幕,可以用来展示更多内容并高效的学习、娱乐或办公。
- 平板可根据用户使用习惯选择横向手持或竖向手持。
- PC/2in1支持全屏或自由窗口显示应用。
- PC/2in1设备融合了屏幕触摸和键鼠的交互方式;平板也可以通过外接方式支持键鼠。
根据平板和PC/2in1的独特属性,本文将从以下几个方面来介绍开发平板和PC/2in1应用过程中的常见问题,并提供推荐的解决方案或开发指导,以满足用户的最佳体验。
- 布局设计:设计合理美观的针对性布局,充分利用大尺寸屏幕,同时展示更多信息。
- 窗口适配:通过支持平板的横竖屏旋转和PC/2in1的自由窗口,满足用户的多样化体验。
- 交互体验:在应用中增加键鼠的交互体验支持。
- 特殊事项:若应用中涉及相机调用,需要注意在平板和PC/2in1上的不同场景和摄像头支持情况。另外,对于没有适配平板的应用,支持使用兼容模式小窗口运行。
说明
开发在平板或PC/2in1设备上运行的应用,需要在module.json5配置文件的module字段中,增加支持的deviceTypes工程配置。例如,适配平板设备需增设“tablet”,适配PC/2in1设备需增设“PC/2in1”。
布局设计
因为平板和PC/2in1拥有独特的大尺寸屏幕优势,开发其应用时推荐使用响应式布局实时响应窗口尺寸变化,确保以最佳的布局来展示内容。
本章节从五个角度介绍平板和PC/2in1中常用的典型布局:
- 侧边导航
- 重复布局
- 挪移布局
- 侧边栏
- 分栏布局
侧边导航栏
当应用窗口宽度 ≥ 840 vp,且窗口宽度 > 高度时,应用的底部导航栏推荐切换为侧边导航栏。
导航页签使用 Tabs 组件实现,其参数barPosition支持设置Tabs的位置,属性vertical支持设置页签是否为纵向。分别设置barPosition和vertical的值,可以将页签设置在父容器的左右侧、顶部或底部。
属性值 | vertical = true | vertical = false |
---|---|---|
barPosition = Start | 容器左侧 | 容器顶部 |
barPosition = End | 容器右侧 | 容器底部 |
开发过程中,设置不同断点下barPosition和vertical的值即可。
在多数场景下,窗口宽度 < 840vp,即窗口非lg断点时,页签位于页面底部,此时vertical = false,barPosition = End。
若窗口宽度 ≥ 840 vp,即窗口为lg断点时,页签位于页面左侧,此时vertical = true,barPosition = Start。
说明
在部分平板设备上,应用处于竖屏状态时,宽度 > 840vp,仍推荐采用底部页签。所以需要增加判断条件:若窗口的宽度 < 高度,页签位于底部;否则位于左侧。
在EntryAbility.ets文件中,开启窗口尺寸变化订阅:
private windowObj?: window.Window;
private onWindowSizeChange: (windowSize: window.Size) => void = (windowSize: window.Size) => {
AppStorage.setOrCreate('windowWidth', windowSize.width);
AppStorage.setOrCreate('windowHeight', windowSize.height);
};
// ...
onWindowStageCreate(windowStage: window.WindowStage) {
// ...
windowStage.getMainWindow().then((data: window.Window) => {
this.windowObj = data;
AppStorage.setOrCreate('windowWidth', data.getWindowProperties().windowRect.width);
AppStorage.setOrCreate('windowHeight', data.getWindowProperties().windowRect.height);
this.windowObj.on('windowSizeChange', this.onWindowSizeChange);
// ...
});
// ...
}
在页面文件中设置Tabs组件的位置:
@StorageLink('windowWidth') windowWidth: number = 0;
@StorageLink('windowHeight') windowHeight: number = 0;
Tabs({
// lg断点且横屏时为Start,其他场景时为End
barPosition: (this.currentWidthBreakpoint === BreakpointConstants.BREAKPOINT_LG && this.windowWidth > this.windowHeight) ?
BarPosition.Start : BarPosition.End
}) {
// ...
}
// lg断点且横屏时为纵向Tabs,其他场景时为横向Tabs
.vertical(this.currentWidthBreakpoint === BreakpointConstants.BREAKPOINT_LG && this.windowWidth > this.windowHeight)
重复布局
为了提高屏幕利用率,在大屏上展示更多的内容信息,使用以下容器组件时,可以根据断点展示更多列数实现重复布局。
- 列表
List组件提供 lanes 属性,支持设置布局列数或行数。通常,在lg断点下,需要通过该属性设置更多列数。
例如,在大屏设备上的列表项展示为3列,其他设备上展示为2列。
List() {
// ...
}
// 设置不同断点下的列数,sm和md断点下为2,lg断点下为3
.lanes(this.currentWidthBreakpoint === BreakpointConstants.BREAKPOINT_LG ? 3 : 2)
- 瀑布流
WaterFlow组件提供 columnsTemplate 属性,支持设置当前瀑布流组件布局的列的数量。
通常,相较于sm和md断点,瀑布流组件在lg断点下呈现更多列展示。例如,组件在lg断点下展示3列,其他断点下展示2列。
若希望其中某列占据大于均值的宽度,也可以通过该属性的传参进行配置。例如,传入参数为’1fr 1fr 2fr’,表示将父组件的宽度等分为4份,其中三列分别占据1份、1份、2份。
WaterFlow() {
// ...
}
// sm和md断点下均分为2列,lg断点下分为3列,且分别占据父组件宽度的1/4、1/4、2/4
.columnsTemplate(this.currentBreakpoint !== Breakpoint.BREAKPOINT_LG ? '1fr 1fr' : '1fr 1fr 2fr')
- 轮播图片
Swiper 组件提供子组件滑动轮播显示的能力,可以用来实现轮播图片。
一般情况下,在lg断点时,应用的轮播图片需要展示多张,且左右两端展示前后两张图片的部分内容。
通过Swiper组件的 displayCount 属性,可以设置视窗内图片显示的个数;设置 itemSpace 属性,即可设置组件内子组件之间的间隙。
设置后边距( nextMargin )和前边距( prevMargin )的值,可以展示前后项的部分内容,在视觉上呈现延展的效果。
此外,在适配大屏设备时,若Swiper内组件因为窗口宽高的变化出现拉伸变形等问题,可以使用 aspectRatio 属性,指定组件宽高比,使组件自适应缩放,保证页面的正常显示。
Swiper() {
ForEach(list, (item: Image) => {
Image(item)
// 宽高按照预设的比例,随容器组件发生变化且宽高比不变
.aspectRatio(new BreakpointType(1.5, 1.83, 2.33).getValue(this.currentWidthBreakpoint))
// ...
})
}
// 设置在sm断点下展示1张图片,其他断点下展示2张
.displayCount(this.currentWidthBreakpoint === BreakpointConstants.BREAKPOINT_SM ? 1 : 2)
// 设置子组件的间隙
.itemSpace(12)
// 设置前后边距,不同断点下边距不同
.prevMargin(new BreakpointType(0, 12, 64).getValue(this.currentWidthBreakpoint))
.nextMargin(new BreakpointType(0, 12, 64).getValue(this.currentWidthBreakpoint))
// ...
- 网格
网格布局通过 Grid 组件实现。在不同断点下,设置不同的列数( columnsTemplate )和行数( rowsTemplate),即可呈现网格的多端效果。
类似于瀑布流组件,网格同样支持设置某列/行占据父组件宽/高的比例。
与轮播图片相同,为了保证网格的内容正常显示,避免出现图片拉伸、内容变形等问题,可以给网格内组件设置属性 aspectRatio ,指定组件宽高比,实现组件的自适应缩放。
Grid() {
ForEach(list, (item: Image) => {
GridItem() {
Image(item)
// 宽度和高度随着容器组件的变化而变化,而纵横比保持不变
.aspectRatio(1.7)
// ...
}
})
}
// 设置网格布局列数并均匀划分宽度
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr')
挪移布局
在一些特殊场景下,页面在sm断点下呈现上下布局,在lg断点下呈现左右布局。
此时需要借助栅格组件 GridRow 和 GridCol,配置在不同断点下栅格子元素占据的列数。当一行中的列数超过栅格组件在该断点的总列数时,可以自动换行,实现挪移布局效果。
在开发中,应用根据具体设计,规划在不同断点下子元素占用的列数即可。
GridRow({
// 栅格数4、12、12列
columns: { sm: 4, md: 12, lg: 12 }
}) {
GridCol({
// 子元素A在不同断点分别占用4、4、4列
span: { sm: 4, md: 4, lg: 4 }
}) {
// 子元素A
}
GridCol({
// 子元素B在不同断点下分别占用4、8、8列
span: { sm: 4, md: 8, lg: 8 }
}) {
// 子元素B
}
}
呈现效果:
侧边栏
在大屏设备上,可以使用 SideBarContainer 组件展示侧边栏,显示更多内容,便于用户操作。
该组件需要传入两个子组件,分别表示侧边栏区域和内容区域,对应上图中右侧深色区域和左侧浅色区域。
在lg断点下设置 showSideBar 为true,显示侧边栏;其他断点下根据应用需要进行配置即可。
设置属性 sideBarPosition 的值,控制侧边栏显示在容器左侧/右侧,默认位于左侧;示意图中设置其为SideBarPosition.End,表示侧边栏位于容器右侧。
通过属性 sideBarWidth 设置侧边栏宽度的初始值;侧边栏支持通过拖拽改变宽度,需要设置其最大宽度 maxSideBarWidth 和最小宽度 minSideBarWidth ,并在通用事件 onAreaChange 中实现侧边栏宽度变更时的逻辑处理。
SideBarContainer() {
Column() {
// 侧边栏区域内容
}
.onAreaChange((newValue: Area) => {
if (newValue.width !== 0) {
// 侧边栏宽度发生变更时的处理
}
})
Column() {
// 内容区域
}
}
.showSideBar(this.currentWidthBreakpoint === BreakpointConstants.BREAKPOINT_LG ? true : false)
.sideBarWidth(320)
.minSideBarWidth(320)
.maxSideBarWidth(500)
分栏布局
应用在平板和PC/2in1设备上支持单双栏、三分栏布局,组合使用 Navigation 组件和 SideBarContainer 组件即可实现。
窗口适配
由于用户的使用习惯不同,在使用平板时可能选择横向手持或竖向手持,所以平板上的应用需要支持横竖屏旋转;PC/2in1设备上的应用需要支持全屏或自由窗口、自定义窗口标题栏以及沉浸式体验,满足用户的多样化体验。
- 横竖屏旋转适配:对于横竖屏旋转适配场景,应用可以根据具体的需求规格采用不同的适配方案。
- 应用窗口化适配:在应用适配PC/2in1设备时,应用从桌面启动,应默认以非全屏的窗口显示,且窗口大小支持通过自由拖动改变。
- 应用窗口化标题栏适配:在PC/2in1设备上,应用窗口的标题栏需要支持沉浸式和自定义。
- 自由窗口的全屏沉浸式适配:在视频类应用适配PC/2in1设备时,需要支持自由窗口与全屏沉浸式体验。
交互体验
平板和PC/2in1设备上的应用,需要考虑更多交互场景,适配触控屏和键鼠的交互方式。
常见交互事件包含以下4个方面:
- 交互归一:在平板和PC/2in1设备上,应用应保证用户体验与其他设备上保持一致。
- 鼠标悬浮效果:参考大屏应用交互体验标准,在平板和PC/2in1设备上的应用中,所有支持交互的UI组件,都需要适配鼠标悬浮效果。开发方案请参考悬浮场景。
- 焦点导航:设备接入键盘后,应用应支持通过键盘实现焦点导航,指示用户当前焦点位置。开发方案请参考焦点导航事件适配。
- 键盘快捷键:应用需要支持响应常用快捷键,便于用户快速操作。
特殊事项
相机适配
若应用中涉及相机功能,为了确保相机拉起后,图像方向角度正常且不会出现内容挤压等异常情况,在平板和PC/2in1进行适配时需要充分考虑以下场景:
- 平板:平板设备上拉起相机的页面时,除了需要考虑在横竖屏状态下的布局以外,还要考虑在自由窗口、分屏、悬浮窗等多窗口场景下的布局。
- PC/2in1:PC/2in1设备上没有后置摄像头,在拍照、录像及扫一扫等场景中,建议适配方案如下:
说明
使用PC/2in1设备的相机功能时,需要在设置-系统-开发人员选项菜单中关闭USB调试功能。请确认系统相机APP可以正常使用,再调试应用的相机功能。
兼容模式
若应用没有适配平板设备的计划,可以采用兼容模式,在平板上以小窗口的形式运行。
若采用此模式,需要按照以下步骤:
- 应用开发时,工程的module.json5文件中,支持的设备类型字段中不添加tablet。
- 在发布应用时,需要在 配置支持设备 时,选择在平板设备上兼容。