挪移布局与缩进布局概述
| 布局类型 | 实现方案 |
|---|---|
| 插图和文字组合布局 | GridRow/GridCol 组件 + 断点 + 栅格 |
| 底部/侧边导航 | SideBarContainer 组件 + 断点 |
| 单列列表布局 | GridRow/GridCol 组件 + 断点 + 栅格 |
挪移布局
挪移布局是指在空间充足时,通过调整组件的位置与展示方式,在左右布局与上下布局之间切换,用以展示更多内容或提高用户体验。常用的挪移布局包括插图和文字组合布局、底部/侧边导航。
插图和文字组合布局
插图和文字组合布局基于横向断点,设置组件所占不同的栅格数,实现左右布局与上下布局的切换。
布局效果

实现方案
设置不同横向断点下,GridRow 组件的 columns、breakpoints 属性,和 GridCol 组件的 span 属性实现目标效果。
示例代码
GridRow({
columns: { xs: 4, sm: 4, md: 8, lg: 12, xl: 12 },
gutter: 0,
breakpoints: { value: ['320vp', '600vp', '840vp', '1440vp'] },
direction: GridRowDirection.Row
}) {
GridCol({
span: { xs: 4, sm: 4, md: 4, lg: 4, xl: 4 },
offset: 0
}) {
// ...
}
.height(this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_SM ? this.getGridColHeight() : '100%')
.padding({ top: this.getUIContext().px2vp(this.mainWindowInfo.AvoidSystem?.topRect.height) + 12 })
.backgroundColor('#AAD3F1')
GridCol({
span: { xs: 4, sm: 4, md: 4, lg: 8, xl: 8 },
offset: 0
}) {
// ...
}
.backgroundColor(Color.Pink)
.layoutWeight(1)
.padding({ top: this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_SM ? 0 : this.getUIContext().px2vp(this.mainWindowInfo.AvoidSystem?.topRect.height) })
}
代码解析:
- 初始化网格布局:使用
GridRow组件初始化一个网格行,设置了列的数量、间距和断点,方向为行方向。 - 定义第一个网格列:使用
GridCol定义一个网格列,设置列在不同屏幕尺寸下的跨度和偏移量。设置列的高度和内边距,根据屏幕宽度调整高度和内边距的值。设置背景颜色为#AAD3F1。 - 定义第二个网格列:使用
GridCol定义另一个网格列,设置列在不同屏幕尺寸下的跨度和偏移量。设置背景颜色为粉色。设置布局权重为 1,根据屏幕宽度调整内边距的值。 - 布局适应性:通过
breakpoints和span的设置,确保布局在不同屏幕尺寸下都能自适应显示。使用layoutWeight来控制列的布局权重,影响在多余空间的分配。
此布局场景也常用于页面顶部页签与搜索框,具体可参考如下布局效果。

底部/侧边导航
底部/侧边导航基于横向断点,设置导航栏的位置与方向,实现上下布局与左右布局的切换。
电脑设备上的商务办公、实用工具垂类应用开发中,常使用侧边分级导航展示多级目录。而在一多开发时,侧边分级导航并不一定适用于手机、平板等设备,若需要实现导航栏内的分级效果,比较复杂。
当前系统支持手机、折叠屏、平板和电脑四种产品形态,分别对应 sm、md、lg 和 xl 四个断点,下文将实现不同断点下的分级导航栏。
布局效果

当断点为 sm 或 md 时,显示底部导航和顶部页签;当断点为 lg 时,显示左侧导航;当断点为 xl 或设备为 PC/2in1 时,侧边显示一级和二级导航。
实现方案
开发一多分级导航栏时,需要实现 4 种断点下的一多效果:
- 订阅窗口尺寸变化,更新断点,触发页面布局更新。
- 在 sm 和 md 断点下,分级导航由底部一级导航栏和顶部二级页签组成。
- 在 lg 断点下,分级导航由侧边一级导航栏和顶部二级页签组成。
- 使用电脑设备或 xl 断点下,通过侧边栏显示一级和二级导航。
设置不同横向断点下,Tabs 组件的 barPosition、vertical、barHeight、barWidth 和 barMode 属性实现目标效果。
示例代码
在 sm、md 和 lg 断点下,在首页调用 Tabs 组件,渲染一级导航目录信息到页签,并在内容区域调用已实现的页面视图,实现页面效果。
// entry/src/main/ets/view/TabsView/TabsView.ets
Tabs({ barPosition: this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_LG ? BarPosition.Start : BarPosition.End }) {
TabContent() {
TopTabView({ pageInfos: this.pageInfos, mainWindowInfo: this.mainWindowInfo, firstLevelIndex: this.firstLevelIndex, tabData: this.tabData })
.tabBar(this.tabBuilder(this.firstTabList[0], 0))
}
TabContent()
.tabBar(this.tabBuilder(this.firstTabList[1], 1))
TabContent()
.tabBar(this.tabBuilder(this.firstTabList[2], 2))
TabContent()
.tabBar(this.tabBuilder(this.firstTabList[3], 3))
}
.barBackgroundColor('#CCF1F3F5')
.barWidth(this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_LG ? 96 : '100%')
.barHeight(this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_LG ? '100%' : 56 + this.getUIContext().px2vp(this.mainWindowInfo.AvoidNavigationIndicator?.bottomRect.height))
.barMode(this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_LG ? BarMode.Scrollable : BarMode.Fixed, { nonScrollableLayoutStyle: LayoutStyle.ALWAYS_CENTER })
.barBackgroundBlurStyle(BlurStyle.COMPONENT_THICK)
.vertical(this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_LG)
.onChange((index: number) => {
this.firstLevelIndex = index;
})
- Tabs 组件初始化:创建一个 Tabs 组件,选项卡栏的位置基于
mainWindowInfo.widthBp的值。如果是宽窗口(WIDTH_LG),则选项卡栏在顶部(BarPosition.Start),否则在底部(BarPosition.End)。 - TabContent 定义:定义了四个 TabContent 组件,每个组件都有一个自定义的标签栏。标签栏的构建使用
tabBuilder方法,传入不同的参数来生成不同的标签。 - 标签栏样式设置:设置选项卡栏的背景颜色、宽度、高度、模式和背景模糊样式。这些样式根据窗口宽度断点动态调整。
- 选项卡切换事件处理:当选项卡切换时,更新
firstLevelIndex的值,以反映当前选中的选项卡索引。 - 布局方向设置:根据窗口宽度断点,设置布局的方向是垂直还是水平。
在 xl 断点下或使用 PC/2in1 设备,首页调用 SideBarContainer 组件,传入侧边栏区域组件和内容区域组件。此时可以结合 @State 和 @Link 装饰器,同步所需要的参数信息,如当前选中的一级目录索引和二级目录索引,可以用于呈现与页签强相关的页面内容。
// entry/src/main/ets/view/TabsView/TabsView.ets
if ((this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_LG || this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_XL) && deviceInfo.deviceType == "2in1") {
// Use SideBarContainer at XL breakpoint.
SideBarContainer(SideBarContainerType.Embed) {
TabSideBarView({
firstLevelIndex: this.firstLevelIndex,
secondLevelIndex: this.secondLevelIndex,
tabData: this.tabData,
firstTabList: this.firstTabList
})
Column() {
Row() {
Text(this.tabViewModel.getTabNameOfSecondLevel(
this.tabViewModel.getTabNameOfFirstLevel(this.firstLevelIndex),
this.secondLevelIndex
))
.fontSize('20fp')
.fontWeight(700)
.margin({ left: 16 })
}
.padding({ top: 60, bottom: 14 })
VideoInfoView({
mainWindowInfo: this.mainWindowInfo,
firstLevelIndex: this.firstLevelIndex,
secondLevelIndex: this.secondLevelIndex
})
}.alignItems(HorizontalAlign.Start)
}
.autoHide(false)
.divider({ strokeWidth: 0.3 })
.showControlButton(false)
.sideBarWidth(240)
.minSideBarWidth(240)
.maxSideBarWidth(240)
} else {
// ... 其他断点逻辑
}
- 条件判断:代码首先检查当前设备的屏幕宽度是否为较大的断点(
WIDTH_LG或WIDTH_XL),并且设备类型是否为'2in1'。如果条件满足,则进入侧边栏布局的逻辑。 - 侧边栏容器:当条件满足时,创建一个
SideBarContainer,类型为Embed。在这个容器中,首先实例化TabSideBarView,传入相关的参数。 - 内容布局:在
SideBarContainer内部,使用Column和Row组件来组织布局。Row中包含一个Text组件,用于显示标签名称,设置了字体大小、字体粗细和左边距。Column中包含两个子组件:Row和VideoInfoView,分别用于显示文本信息和视频信息。 - 样式和属性设置:为
Row和Column设置了一些样式和属性,如填充、对齐方式、边距等。 - 侧边栏属性:为
SideBarContainer设置了一些属性,如是否自动隐藏、分隔线宽度、控制按钮显示状态、侧边栏宽度等。
缩进布局
缩进布局是指在空间充足时,组件居中展示并在两侧留白,通过调整内容的缩进来建立视觉层次结构,提高可读性和美观性。常用的缩进布局包括单列列表布局。
单列列表布局
单列列表布局基于横向断点,设置栅格子组件所占的栅格列数和偏移列数,实现缩进布局。
布局效果

实现方案
设置不同横向断点下,GridRow 组件的 columns、breakpoints 属性和 GridCol 组件的 span、offset 属性实现目标效果。
示例代码
GridRow({
columns: { xs: 4, sm: 4, md: 8, lg: 12, xl: 12 },
gutter: 0,
breakpoints: { value: ['320vp', '600vp', '840vp', '1440vp'] },
direction: GridRowDirection.Row
}) {
GridCol({
span: { xs: 4, sm: 4, md: 6, lg: 8, xl: 8 },
offset: { xs: 0, sm: 0, md: 1, lg: 2, xl: 2 }
}) {
// ...
}
.width('100%')
.height('100%')
}
- GridRow 组件定义:创建了一个 GridRow 组件,设置了列数(columns)和间距(gutter)。columns 属性定义了不同屏幕尺寸下的列数,如 xs、sm、md、lg、xl 分别对应 320vp、600vp、840vp、1440vp 的设备。gutter 属性设置为 0,表示列之间的间距为 0。breakpoints 属性定义了不同屏幕尺寸下的断点,用于调整布局。direction 属性设置为 GridRowDirection.Row,表示布局方向为行。
- GridCol 组件定义:在 GridRow 中定义了一个 GridCol 组件,设置了列的跨度(span)和偏移(offset)。span 属性定义了不同屏幕尺寸下的列跨度,如 xs、sm、md、lg、xl 分别对应 320vp、600vp、840vp、1440vp 的设备。offset 属性定义了不同屏幕尺寸下的列偏移,如 xs、sm、md、lg、xl 分别对应 320vp、600vp、840vp、1440vp 的设备。
- 样式设置:对 GridCol 组件设置了宽度(.width('100%))和高度(.height('100%)),使其在不同设备上占据整个父容器的空间。

