HarmonyOS鸿蒙Next中Sidebar侧边栏使用问题

HarmonyOS鸿蒙Next中Sidebar侧边栏使用问题 navigation分栏(整个应用就一个)、tabs和Sidebar怎么一起使用(底部tabs首页可以使用侧边栏,其他没有),
就是做成图一图二那样,图片分别为平板和手机样式,可以给个demo吗?

图一

图二


更多关于HarmonyOS鸿蒙Next中Sidebar侧边栏使用问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

7 回复

开发者您好,提供如下demo供参考:

【解决方案】

1、实现Navigation+侧边栏,且分栏效果需要跟随屏幕大小而变化,可以参考示例代码基于一多能力实现响应式布局中的“三分栏”效果; 2、结合Tabs组件,且小屏TabBar在下方,大屏TabBar在左侧;Tabs只有第一个页签需要展示侧边栏,可以修改示例代码中的TripleColumnView文件,修改后如下所示(仅在外层添加Tabs、TabContent组件和vertical属性):

import { WidthBreakpointType } from '../utils/WidthBreakpointType';
import { WindowInfo } from '../utils/WindowUtil';
import { NavigationBarView } from './NavigationBarView';
import { NavigationContent1, NavigationContent2 } from './NavigationContentView';
@Preview
@Component
export struct TripleColumnView {
  @ObjectLink @Watch('widthBpChange') mainWindowInfo: WindowInfo;
  @State isShowingSidebar: boolean = this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_LG ||
    this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_XL ? true : false;
  pageInfos: NavPathStack = new NavPathStack();
  pathStack: NavPathStack = new NavPathStack();

  widthBpChange(): void {
    if (this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_LG ||
      this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_XL) {
      this.isShowingSidebar = true;
    } else {
      this.isShowingSidebar = false;
    }
  }

  @Builder
  PageMap(name: string) {
    if (name === 'navigationContent1') {
      NavigationContent1({
        mainWindowInfo: this.mainWindowInfo,
        isTripleView: true
      })
    } else if (name === 'navigationContent2') {
      NavigationContent2({ mainWindowInfo: this.mainWindowInfo })
    }
  }

  build() {
    Tabs({ barPosition: this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_SM ? BarPosition.End : BarPosition.Start }) {
      TabContent() {
        SideBarContainer(new WidthBreakpointType(SideBarContainerType.Overlay, SideBarContainerType.Overlay,
          SideBarContainerType.Embed, SideBarContainerType.Embed).getValue(this.mainWindowInfo.widthBp)) {
          Column() {
            // [StartExclude triple_column_view]
            Image($r('app.media.open_sidebar'))
              .width(40)
              .height(40)
              .onClick(() => {
                this.isShowingSidebar = !this.isShowingSidebar;
              })
            Column() {
              Text('SidebarContainer')
                .fontSize(18)
                .margin({ bottom: 12 })
              Text($r('app.string.side_bar'))
                .fontSize(24)
            }
            .width('100%')
            .layoutWeight(1)
            .justifyContent(FlexAlign.Center)

            // [EndExclude triple_column_view]
          }
          // [StartExclude triple_column_view]
          .alignItems(HorizontalAlign.Start)
          .backgroundColor('#FFD6B5D6')
          .width('100%')
          .height('100%')
          .padding({
            top: this.getUIContext().px2vp(this.mainWindowInfo.AvoidSystem?.topRect.height) + 12,
            bottom: this.getUIContext().px2vp(this.mainWindowInfo.AvoidNavigationIndicator?.bottomRect.height),
            left: 16,
            right: 16
          })

          // [EndExclude triple_column_view]

          Column() {
            Navigation(this.pathStack) {
              NavigationBarView({
                mainWindowInfo: this.mainWindowInfo,
                pageInfos: this.pageInfos,
                pathStack: this.pathStack,
                isShowingSidebar: this.isShowingSidebar,
                isTriView: true
              })
            }
            .width('100%')
            .height('100%')
            .mode(this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_SM ? NavigationMode.Stack :
              NavigationMode.Split)
            .navBarWidth(this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_MD ? '50%' : '40%')
            .navDestination(this.PageMap)
            .backgroundColor('#B8EEB2')
          }
          // [StartExclude triple_column_view]
          .width('100%')
          .height('100%')

          // [EndExclude triple_column_view]
        }
        .showSideBar(this.isShowingSidebar)
        .sideBarWidth(new WidthBreakpointType('80%', '50%', '20%', '20%').getValue(this.mainWindowInfo.widthBp))
        // [End triple_column_view]
        .controlButton({ top: this.getUIContext().px2vp(this.mainWindowInfo.AvoidSystem?.topRect.height) + 12 })
        .showControlButton(false)
        .autoHide(false)
      }
      .tabBar("首页")
      TabContent() {
        Text("详情")
      }
      .tabBar("详情")
      TabContent() {
        Text("我的")
      }
      .tabBar("我的")
    }
    .vertical(this.mainWindowInfo.widthBp === WidthBreakpoint.WIDTH_SM ? false : true)
  }
}

上述代码可以实现当检测到小屏时,tabBar在最下方,大屏时设置横向显示tabBar并出现在左侧

更多关于HarmonyOS鸿蒙Next中Sidebar侧边栏使用问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


navigation放在tabs里面,在手机打开二级页面底部tabs还在吧,

开发者您好,以上提供demo中进入“三分栏”后,tabs会一直存在的,如果跟您的需求不符,请提供以下信息:具体的业务场景以及目前提供的demo与期望有哪些不符。

参考我的华为APP布局(除了多了个左右分栏布局),

import { HdsSideMenu, HdsSideMenuMainItem, HdsSideMenuSubItem, HdsSideMenuBadgeParam, HdsSideBar } from '@kit.UIDesignKit';
import { SymbolGlyphModifier } from '@kit.ArkUI';
@Entry
@ComponentV2

struct Index {

  @Local showControlButton: boolean = true;

  @Local sideBarMask: boolean = false;

  @Local autoHide: boolean = true;

  @Local barStateTypeText: string = "Select BarState";

  @Local widthIndex: number = 0;

  @Local badgeNumber: HdsSideMenuBadgeParam = { count: 50 };

  @Local useTheme: boolean = false;

  @Local selectedIndex: number = 2;

  @Local selectedTransparency: number = 0.6;

  @Local str: string = "短信";

  @Local isShowSidebar: boolean = true;

  listOptionsDefault?: HdsSideMenuMainItem[] = [

    new HdsSideMenuMainItem(

      {

        symbol: new SymbolGlyphModifier($r('sys.symbol.ohos_folder_badge_plus')).fontSize(14),

        label: $r('sys.string.TextView_engr_phone'),

      }),

    new HdsSideMenuMainItem({

      icon: $r('sys.symbol.person_wave_3'),

      label: 'Tuesday',

      hdsSideMenuSubItem: [

        new HdsSideMenuSubItem({ label: this.str, badge: this.badgeNumber })],

    }),

    new HdsSideMenuMainItem({

      symbol: new SymbolGlyphModifier($r('sys.symbol.person_crop_circle_fill_1')),

      label: 'Wednesday',

    }),

  ]

  @Builder

  SideBarPanelBuilder() {

    Column() {

      HdsSideMenu({

        items: this.listOptionsDefault,

        selectedIndex: this.selectedIndex,

        $selectedIndex: (selectedIndex: number) => {

          this.selectedIndex = selectedIndex;

        },

      })

    }

    .height('100%')

  }

  //右侧内容区

  @Builder

  ContentPanelBuilder() {

    Column() {

      Column() {

        Button() {

          SymbolGlyph(this.isShowSidebar ? $r('sys.symbol.open_sidebar') : $r('sys.symbol.close_sidebar'))

            .fontWeight(FontWeight.Normal)

            .fontSize($r('sys.float.ohos_id_text_size_headline7'))

            .fontColor([$r('sys.color.ohos_id_color_titlebar_icon')])

            .hitTestBehavior(HitTestMode.None)

        }

        .backgroundColor($r('sys.color.ohos_id_color_button_normal'))

        .height(24)

        .width(24)

        .animation({ curve: Curve.Sharp, duration: 100 })

        .onClick(() => {

          this.isShowSidebar = !this.isShowSidebar;

        })

      }

    }

    .height('100%')

    .width('100%')

  }

  @BuilderParam sideBarBuilder: () => void = this.SideBarPanelBuilder

  @BuilderParam contentBuilder: () => void = this.ContentPanelBuilder

  @Builder

  build() {

    Column() {

      HdsSideBar({

        sideBarPanelBuilder: (): void => {

          this.sideBarBuilder()

        },

        contentPanelBuilder: (): void => {

          this.contentBuilder()

        },

        isShowSideBar: this.isShowSidebar,

        $isShowSideBar: (isShowSidebar: boolean) => {

          this.isShowSidebar = !isShowSidebar

        },

      })

    }

  }

}

首先:版本需要从6.0.0(20) Beta1及以上,HdsSideMenu提供一种菜单栏样式组件。设置侧边栏对应的一级菜单和二级菜单,并显示其新消息数量。 参考:侧边栏菜单样式-UI Design Kit(UI设计套件)-应用框架 - 华为HarmonyOS开发者或者侧边栏样式-UI Design Kit(UI设计套件)-应用框架 - 华为HarmonyOS开发者

HarmonyOS Next中Sidebar侧边栏通过@Entry@Component装饰的组件构建。使用SidebarContainer接口创建容器,通过sidebar参数设置侧边栏内容,content参数设置主内容。侧边栏可控制显示/隐藏,支持通过手势或按钮触发。其宽度可自适应调整,并提供了controlButton属性用于自定义控制按钮。开发者需在aboutToAppear生命周期中初始化侧边栏状态。

在HarmonyOS Next中实现你描述的布局(全局navigation分栏 + 底部tabs + 仅首页支持Sidebar侧边栏),核心思路是采用组合式导航结构,并动态控制Sidebar的显示。以下是一个关键代码示例和实现逻辑:

1. 整体架构设计 使用 NavDestinationStack 作为根容器管理全局分栏,内部嵌套 Tabs 组件实现底部页签,在首页的页面组件中条件渲染 SidebarContainer

2. 示例代码框架

// 主入口:组合导航结构
@Entry
@Component
struct MainPage {
  @State currentTab: number = 0

  build() {
    NavDestinationStack() {
      // 第一栏:带Tab和Sidebar的主界面
      NavDestination() {
        HomeTabPage({ currentTab: $currentTab }) // 首页Tab容器
      }
      .title('首页')

      // 第二栏:其他分栏页面(无需Sidebar)
      NavDestination() {
        OtherColumnPage()
      }
      .title('其他')
    }
    .mode(NavigationMode.Split)
  }
}

// 首页Tab容器
@Component
struct HomeTabPage {
  @Link currentTab: number
  @State showSidebar: boolean = false // 控制侧边栏显示

  build() {
    Tabs({ barPosition: BarPosition.End, index: this.currentTab }) {
      // 首页Tab:包含Sidebar
      TabContent() {
        Column() {
          // 内容区
          Text('首页内容')
          Button('开关侧边栏')
            .onClick(() => { this.showSidebar = !this.showSidebar })
        }

        // 条件渲染侧边栏(仅当前Tab为首页时生效)
        if (this.showSidebar && this.currentTab === 0) {
          SidebarContainer({ sideBarWidth: 240, showSideBar: this.showSidebar }) {
            // 侧边栏内容
            SideBar()
            // 主内容区
            MainContent()
          }
          .onChange((show: boolean) => { this.showSidebar = show })
        }
      }
      .tabBar('首页')

      // 其他Tab页(无Sidebar)
      TabContent() {
        Text('其他页面')
      }
      .tabBar('发现')
    }
  }
}

// 侧边栏组件
@Component
struct SideBar {
  build() {
    Column() {
      Text('侧边栏菜单1')
      Text('侧边栏菜单2')
    }
  }
}

3. 关键控制逻辑

  • Sidebar显示控制:通过 showSidebar 状态变量和条件渲染实现,确保仅在首页Tab激活时可能显示。
  • 设备适配:可在 aboutToAppear 中通过 display.getDefaultDisplaySync() 获取设备信息,动态调整 sideBarWidth 或切换显示模式。
  • 导航联动:当切换至非首页Tab时,自动关闭Sidebar(通过监听 currentTab 变化重置 showSidebar 状态)。

4. 注意事项

  • 避免在多个TabContent中同时声明Sidebar,防止渲染冲突。
  • 平板模式下Navigation分栏宽度可能影响Sidebar显示,需通过 minContentWidth 调整布局断点。
  • 侧边栏交互状态(如展开/收起)建议使用 AppStorage 管理,实现跨组件状态同步。

这种设计实现了分栏导航、底部Tab和条件化侧边栏的分离管理,符合HarmonyOS Next的声明式开发范式。实际开发中需根据具体UI规范调整尺寸和交互细节。

回到顶部