鸿蒙5.0 设备场景实践——平板和PC/2in1开发实践

往期推文全新看点(文中附带全新鸿蒙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 = truevertical = 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可以正常使用,再调试应用的相机功能。

兼容模式

若应用没有适配平板设备的计划,可以采用兼容模式,在平板上以小窗口的形式运行。

若采用此模式,需要按照以下步骤:

  1. 应用开发时,工程的module.json5文件中,支持的设备类型字段中不添加tablet。
  2. 在发布应用时,需要在 配置支持设备 时,选择在平板设备上兼容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值