鸿蒙5.0开发实战案例:一多开发实例(长视频)-UX设计与交互优化
📑往期推文全新看点(文中附带最新·鸿蒙全栈学习笔记)
✒️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?
✒️ 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~
✒️ 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?
✒️ 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?
✒️ 记录一场鸿蒙开发岗位面试经历~
✒️ 持续更新中……
长视频应用全屏播放页为用户带来沉浸式观看视频体验并支持选集。观察全屏播放页在不同设备上的UX设计图,可以进行如下设计:
- 将全屏播放页划分为3个区域,如
| 示意图 | sm | md | lg |
|---|---|---|---|
| 全屏播放页 | ![]() |
![]() |
![]() |
| 全屏播放选集页 | ![]() |
![]() |
![]() |
- 整个页面响应式适配,借助栅格组件能力监听不同断点变化实现不同的布局效果。
- 全屏播放页区域1、2占满屏幕,点击选集弹出区域3,区域2中容器组件尺寸变化时,增大或减小的空间全部分配给进度条和下方工具栏的空白区域。
- 全屏播放页区域3在不同断点下显示位置和大小不同。在sm断点下显示在右侧,视频与侧边栏比例为3:2;在md断点下显示在底部,视频与底部栏比例为1:1;在lg断点下显示在右侧,侧边栏宽度为固定值360vp。
长视频应用全屏播放页的3个基础区域介绍及实现方案如下表所示:
| 区域编号 | 简介 | 实现方案 |
|---|---|---|
| 1 | 全屏视频播放 | 使用 window窗口 管理窗口隐藏状态栏和导航栏,在sm断点下控制窗口横屏显示,在md、lg上不改变窗口显示方向。视频播放使用 AVPlayer 和 XComponent 等相关组件,不详细介绍具体功能实现,读者可以自行查看代码。 |
| 2 | 进度条及工具栏 | 进度条使用layoutWeight、工具栏的空白区域使用Blank实现自适应布局的拉伸能力,同 首页搜索框。 |
| 3 | 选集列表 | 选集列表通过 List组件 实现延伸能力,同 搜索页搜索发现 。 |
在实际开发中,区域1-2和区域3为并列的视频播放页内容,所以对应的开发顺序为区域1-2,区域3。另外,为了提升用户的使用体验,全屏播放页为折叠屏的半折叠态设计了视频悬停播放。
- 全屏视频播放
进入全屏播放页,使用setWindowSystemBarEnable()方法隐藏顶部导航栏和状态栏,并在手机和折叠屏折叠态下使用setMainWindowOrientation()方法设置窗口横屏播放。
// features/VideoPlayer/src/main/ets/view/VideoPlayer.ets
aboutToAppear() {
this.windowUtil = WindowUtil.getInstance();
if (this.windowUtil !== undefined) {
if (deviceInfo.deviceType !== CommonConstants.DEVICE_TYPES[0]) {
// 隐藏顶部导航栏和状态栏
this.windowUtil.disableWindowSystemBar();
}
if ((!display.isFoldable() && deviceInfo.deviceType === CommonConstants.DEVICE_TYPES[2]) ||
display.getFoldStatus() === display.FoldStatus.FOLD_STATUS_FOLDED) {
// 设置窗口横屏播放
this.windowUtil.setMainWindowOrientation(window.Orientation.AUTO_ROTATION_LANDSCAPE);
}
...
} else {
Logger.info(`Full-screen display in portrait mode`);
}
}
- 视频悬停播放
在折叠屏上浏览视频详情页或全屏播放页时,折叠设备,将自动切换至悬停态的沉浸播放视频体验。折叠屏悬停适配通过 window 的setPreferredOrientation接口设置窗口横向显示,通过 display 的getCurrentFoldCreaseRegion接口获取折叠屏折痕区域的位置和大小,通过自定义方式实现悬停态页面。视频移到上半屏,中间为折叠屏避让区,其他可操作组件堆叠到下半屏。示意图如下:
| md |
|---|
![]() |
// commons/base/src/main/ets/utils/DisplayUtil.ets
export class DisplayUtil {
static getFCreaseRegion(): void {
if (display.isFoldable()) {
let foldRegion: display.FoldCreaseRegion = display.getCurrentFoldCreaseRegion();
let rect: display.Rect = foldRegion.creaseRects[0];
// 折叠屏避让区距离顶部高度,避让区本身高度
let creaseRegion: number[] = [px2vp(rect.top), px2vp(rect.height)];
AppStorage.setOrCreate('creaseRegion', creaseRegion);
}
}
}
// features/videoPlayer/src/main/ets/view/VideoPlayer.ets
aboutToAppear() {
...
if (display.isFoldable()) {
// 折叠屏状态为半折叠时,设置窗口横屏显示
if (this.isHalfFolded) {
this.windowUtil.setMainWindowOrientation(window.Orientation.AUTO_ROTATION_LANDSCAPE);
}
}
}
Column() {
Stack({ alignContent: Alignment.Center }) {
Flex({
...
}) {
Column() {
...
}
// 悬停时视频高度为避让区距离顶部高度
.height(this.isHalfFolded ? this.creaseRegion[0] : CommonConstants.FULL_PERCENT)
}
Column() {
...
}
.height(CommonConstants.FULL_PERCENT)
.width(CommonConstants.FULL_PERCENT)
// 主轴尾部对齐,可操作组件堆叠到下半屏
.justifyContent(FlexAlign.End)
.visibility(this.isShowingSideBar ? Visibility.None : Visibility.Visible)
Image($r('app.media.ic_public_back'))
// 返回图标y轴的位置为避让区距离顶部高度+避让区本身的高度
.position({
x: $r('app.float.back_position_x'),
y: this.isHalfFolded ? this.creaseRegion[0] + this.creaseRegion[1] : $r('app.float.back_position_y')
})
}
}
交互开发
交互事件归一
不同类型的智能设备,系统已经针对不同的交互方式做了适配,实现了 交互归一 ,因此开发者无需额外关注用户不同的交互方式。长视频应用包含的基础输入方式如下(以鼠标为例):
| 事件 | 应用支持的鼠标交互 |
|---|---|
| 点击 | 在Tabs、TextInput等组件上点击左键。 |
| 长按 | 在首页首个推荐视频上长按左键预览视频。 |
| 拖拽 | 在视频详情页右侧边栏上按压左键并移动鼠标,改变侧边栏的宽度。 |
| 滚动/平移 | 在List和Scroll组件中上下滚动滚轮,实现。 |
| 缩放 | 在首页推荐视频区域中ctrl+滚动滚轮控制宫格布局的缩放。 |
键盘走焦
在2in1设备的“华为发布会”的搜索结果页面,默认可获焦的组件 遵循走焦规范。点击搜索框进入输入场景时,激活并获焦到输入框。按Tab键,焦点从搜索框向下移动到栅格布局时,默认获焦第一张卡片的播放按钮,再次按Tab键焦点此时可向右移动,到尽头后焦点向上移动至搜索框。同时方向上下键控制焦点在卡片间移动,方向左右键控制焦点在卡片内部和侧边页签间移动。
资源使用
本节以长视频应用为例,根据实际的资源使用情况,给出“一多”应用开发中推荐的资源使用方式。
在长视频应用中,多端页面显示的效果不同,使用的资源值随断点变化,推荐使用 媒体查询 获取资源值。借助媒体查询中监听断点的功能做简单的封装,创建BreakpointType类,通过getValue方法获取对应的资源值。在使用时,创建不同的资源文件传入BreakpointType代表sm、md和lg断点下的资源值,实现应用窗口大小变化时的不同效果。
// commons/base/src/main/ets/utils/BreakpointType.ets
export class BreakpointType<T> {
sm: T;
md: T;
lg: T;
constructor(sm: T, md: T, lg: T) {
this.sm = sm;
this.md = md;
this.lg = lg;
}
getValue(currentBreakpoint: string): T {
if (currentBreakpoint === BreakpointConstants.BREAKPOINT_MD) {
return this.md;
}
if (currentBreakpoint === BreakpointConstants.BREAKPOINT_LG) {
return this.lg;
} else {
return this.sm;
}
}
}
// features/home/src/main/ets/view/DailyVideo.ets
Image($r('app.media.daily_small_video'))
.height(new BreakpointType($r('app.float.small_daily_image_height_sm'),
$r('app.float.small_daily_image_height_md'), $r('app.float.small_daily_image_height_lg'))
.getValue(this.currentBreakpoint))
.width(new BreakpointType($r('app.float.small_daily_image_width_sm'),
$r('app.float.small_daily_image_width_md'), $r('app.float.small_daily_image_width_lg'))
.getValue(this.currentBreakpoint))
功能开发
本示例的目标运行设备手机、折叠屏和2in1运行的都是标准系统,其系统能力一致,所以无需考虑 多设备上应用功能开发 的差异。
总结
本文针对长视频应用沉浸式的核心场景,从UX设计、工程管理、页面开发和功能开发四个角度,结合“一多”各项具体的能力,给出了在开发中推荐的参考样例。同时对于开发者在长视频垂类应用的“一多”开发中经常遇到痛点难点问题,给出详细的解决方案,实现了同类别应用的最佳实践,帮助开发者快速适配多种类型的设备,减少了多端开发的工作量,高效构建应用。

更多推荐










所有评论(0)