【高心星出品】

鸿蒙PC应用开发——挪移布局与缩进布局

插图和文字组合布局 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) })
}

代码逻辑走读:

  1. 初始化网格布局
    • 使用GridRow组件初始化一个网格行,设置了列的数量、间距和断点,方向为行方向。
  2. 定义第一个网格列
    • 使用GridCol定义一个网格列,设置列在不同屏幕尺寸下的跨度和偏移量。
    • 设置列的高度和内边距,根据屏幕宽度调整高度和内边距的值。
    • 设置背景颜色为#AAD3F1
  3. 定义第二个网格列
    • 使用GridCol定义另一个网格列,设置列在不同屏幕尺寸下的跨度和偏移量。
    • 设置背景颜色为粉色。
    • 设置布局权重为1,根据屏幕宽度调整内边距的值。
  4. 布局适应性
    • 通过breakpointsspan的设置,确保布局在不同屏幕尺寸下都能自适应显示。
    • 使用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;
})
  1. Tabs组件初始化
    • 创建一个Tabs组件,选项卡栏的位置基于mainWindowInfo.widthBp的值。如果是宽窗口(WIDTH_LG),则选项卡栏在顶部(BarPosition.Start),否则在底部(BarPosition.End)。
  2. TabContent定义
    • 定义了四个TabContent组件,每个组件都有一个自定义的标签栏。标签栏的构建使用tabBuilder方法,传入不同的参数来生成不同的标签。
  3. 标签栏样式设置
    • 设置选项卡栏的背景颜色、宽度、高度、模式和背景模糊样式。这些样式根据窗口宽度断点动态调整。
  4. 选项卡切换事件处理
    • 当选项卡切换时,更新firstLevelIndex的值,以反映当前选中的选项卡索引。
  5. 布局方向设置
    • 根据窗口宽度断点,设置布局的方向是垂直还是水平。

在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 {
  // ...
}
  1. 条件判断:代码首先检查当前设备的屏幕宽度是否为较大的断点(WIDTH_LGWIDTH_XL),并且设备类型是否为“2in1”。
    • 如果条件满足,则进入侧边栏布局的逻辑。
    • 如果条件不满足,则可能进入其他布局逻辑(代码中未完全展示)。
  2. 侧边栏容器:当条件满足时,创建一个 SideBarContainer,类型为 Embed
    • 在这个容器中,首先实例化 TabSideBarView,传入相关的参数。
  3. 内容布局:在 SideBarContainer内部,使用 ColumnRow组件来组织布局。
    • Row中包含一个 Text组件,用于显示标签名称,设置了字体大小、字体粗细和左边距。
    • Column中包含两个子组件:RowVideoInfoView,分别用于显示文本信息和视频信息。
  4. 样式和属性设置:为 RowColumn设置了一些样式和属性,如填充、对齐方式、边距等。
  5. 侧边栏属性:为 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%')
}
  1. GridRow组件定义
    • 创建了一个GridRow组件,设置了列数(columns)和间距(gutter)。
    • columns属性定义了不同屏幕尺寸下的列数,如xs、sm、md、lg、xl分别对应320vp、600vp、840vp、1440vp的设备。
    • gutter属性设置为0,表示列之间的间距为0。
    • breakpoints属性定义了不同屏幕尺寸下的断点,用于调整布局。
    • direction属性设置为GridRowDirection.Row,表示布局方向为行。
  2. 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的设备。
  3. 样式设置
    • 对GridCol组件设置了宽度(.width(‘100%’))和高度(.height(‘100%’)),使其在不同设备上占据整个父容器的空间。
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐