往期推文全新看点(文中附带全新鸿蒙5.0全栈学习笔录)
✏️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?
✏️ 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~
✏️ 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?
✏️ 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?
✏️ 记录一场鸿蒙开发岗位面试经历~
✏️ 持续更新中……
概述
目前智能终端设备的种类繁多,不同类型的设备屏幕大小、用户使用习惯也存在不同,这给UI布局以及功能适配带来了很多挑战。以分栏布局为例,在手机、折叠屏以及平板下,最佳显示效果存在如下差异:
- 手机仅支持单栏显示
- 折叠屏可以支持单双栏显示
- 平板支持三栏显示
本文提供了一种“通过判断屏幕尺寸,选择合适的分栏布局”的方法,解决HarmonyOS的1+8多种形态设备的UI适配问题。通过该方法,开发者无需关注设备类型,即可达到多设备的自适应分栏布局效果,实现“一次开发,多端部署”。
开发者可以根据屏幕尺寸断点,灵活使用Navigation组件和SidebarContainer组件来实现不同的分栏效果。
分栏实现原理
单双栏:
单双栏通常是使用Navigation实现的,Navigation是路由容器组件,一般作为首页的根容器,包括单栏(Stack)、分栏(Split)和自适应(Auto)三种显示模式。自适应模式下,当页面宽度大于等于一定阈值时,Navigation组件采用分栏模式,反之采用单栏模式。
开发者可以通过更改Navigation组件的mode值来实现单双栏的切换,如果断点为sm,则mode值为Stack。如果不为sm,则mode值为Split,即可实现单双栏的自适应切换。
Navigation(this.pathInfo) {
// ...
}
.mode(this.currentBreakPoint === 'sm' ? NavigationMode.Stack : this.notesNavMode)
三分栏:
Navigation组件实现了单双栏的效果。那么,在更大的屏幕宽度,要实现三分栏效果该如何实现呢?三分栏可以组合使用 SideBarContainer 与 Navigation组件 实现。SideBarContainer提供侧边栏可以显示和隐藏的侧边栏容器,通过子组件定义侧边栏和内容区,第一个子组件表示侧边栏,第二个子组件表示内容区。我们可以在内容区中加入Navigation组件,即可实现三分栏效果。
我们可以通过更改SideBarContainer组件的showSideBar值来控制是否显示侧边栏。如果断点为lg,则showSideBar值为true,默认显示侧边栏,反之,则为false,不显示。
SideBarContainer(SideBarContainerType.AUTO) {
// 导航栏
Column() {
MailSideBar()
}
.width('100%')
.height('100%')
.backgroundColor('#f1f3f5')
// 内容区
Column() {
Stack() {
MailNavigation()
// ...
}
}
.height('100%')
.width('100%')
}
.showSideBar(this.currentBreakPoint === 'lg')
场景案例
典型场景
应用页面有层级关系,例如一级目录、二级目录、内容区,典型的场景比如日常使用的邮箱功能。
邮箱是分为三个层级目录,第一层级为账户信息,第二层级为邮件列表(一个账户信息对应多条邮件信息),第三层级为邮件详情,是一个很典型的三分栏场景。根据内容的重要性,开发者通常在单栏显示邮件详情,双栏显示邮件列表、邮件详情,三栏显示账户、邮件列表、内容区。
对于邮箱页面的一多分栏变化,开发者可以抽象为
示例代码
- 对SideBarContainer组件的showSideBar属性进行赋值,如果断点为lg,则默认显示侧边栏,反之,则默认不显示。
// entry/src/main/ets/application/MailBox.ets
build() {
// ...
SideBarContainer(SideBarContainerType.AUTO) {
// 导航栏
Column() {
MailSideBar()
}
.width('100%')
.height('100%')
.backgroundColor('#f1f3f5')
// 内容区
Column() {
Stack() {
MailNavigation()
// ...
}
}
.height('100%')
.width('100%')
}
.showSideBar(this.currentBreakPoint === 'lg')
// ...
}
- 在SideBarContainer组件内容区中使用Navigation组件,对Navigation组件的mode属性进行赋值,如果断点为sm,则为单栏,反之则为双栏。
// entry/src/main/ets/common/MailNavigation.ets
build() {
Navigation(this.pathInfo) {
// ...
}
.mode(this.currentBreakPoint === 'sm' ? NavigationMode.Stack : this.notesNavMode)
.navDestination(this.myRouter)
// ...
}
其他场景
大部分情况下,单栏展示的是Navigation的内容区,但是存在某些场景,内容区的优先级比导航区的优先级要低,比如日历日程功能,在单栏的情况下,展示的是日历(Navigation的导航区)。效果如下。
日历日程分为三个层级,账户消息->日历->日程,开发者通常在单栏显示日历,双栏显示日历、日程,三栏显示账户信息、日历、日程。日历日程页面与邮箱页面的主要区别为,日历日程页面的单栏页面显示Navigation导航栏。
示例代码
在Navigation的onNavigationModeChange属性中进行判断,当Navigation首次显示或者单双栏状态发生变化时。
- 如果是单栏,则清空PathInfo路由,则Navigation的内容区不显示,即可实现单屏显示Navigation导航栏的目的。
- 如果为双栏,则重新向PathInfo路由中push内容区参数,即可达到单栏变双栏的目的。
Navigation(this.calendarPageInfos) {
CalendarView()
}
.navDestination(this.pageMap)
.mode(this.breakPoint === CommonConstants.BREAK_POINT_SM ? NavigationMode.Stack : this.navMode)
// ...
.onNavigationModeChange((mode: NavigationMode) => {
if (this.breakPoint === CommonConstants.BREAK_POINT_SM || mode === NavigationMode.Stack) {
this.calendarPageInfos.clear();
} else if (mode === NavigationMode.Split) {
this.calendarPageInfos.pushPath({ name: this.selectedItem.date, param: this.selectedItem }, false);
}
})
还有一种SideBarContainer在页面右边的场景,比如大多数页面的智能客服场景。通过sidebarposition属性设置侧边栏右侧显示。