[Harmony]自定义导航栏

1.方案一

CustomNavigationBar

TypeScript 复制代码
import { router } from '@kit.ArkUI';
import { DevicesUtil } from '../utils/DevicesUtil';
import { common } from '@kit.AbilityKit';

@Component
export struct CustomNavigationBar {
  @State private navHeight: number = 44
  @State parTitle: string = ''
  @State parBGColor: Color = Color.White
  private context = getContext(this) as common.UIAbilityContext;
  onHeightChange?: (height: number) => void

  aboutToAppear() {
    DevicesUtil.getStatusBarHeight(this.context).then(height => {
      this.onHeightChange?.(height + this.navHeight) // 触发回调
    })
  }

  build() {
    Column({ space:0 }) {
      Stack(){
        Row({ space: 0 }) {
          Image($r('app.media.icon_base_back'))
            .objectFit(ImageFit.Contain)
            .width(44)
            .height(44)
            .padding(12)
            .onClick(() => router.back())

          Image($r('app.media.icon_nav_logo'))
            .objectFit(ImageFit.Contain)
            .width(64)
            .height(44)
            .padding({ right: 10 })
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)
        .backgroundColor(Color.Transparent)

        Row({ space: 0 }) {
          Text(this.parTitle)
            .fontSize(17)
            .fontColor($r('app.color.mf_base_333333'))
            .fontWeight(FontWeight.Bold)
        }
        .justifyContent(FlexAlign.Center)
        .backgroundColor(Color.Transparent)
      }
      .width('100%')
      .height(this.navHeight)
    }
    .width('100%')
    .backgroundColor(this.parBGColor)
    .expandSafeArea( [SafeAreaType.SYSTEM], [SafeAreaEdge.TOP] )
  }

}

示意图

2.方案二

CustomNavigationBar

TypeScript 复制代码
import { router, window } from '@kit.ArkUI';
import { DevicesUtil } from '../utils/DevicesUtil';
import { common } from '@kit.AbilityKit';

@Component
export struct CustomNavigationBar {
  @State private statusBarHeight: number = 24 // 默认值(vp)
  @State private navHeight: number = 44
  @State parTitle: string = ''
  @State parBGColor: Color = Color.White
  private context = getContext(this) as common.UIAbilityContext;
  onHeightChange?: (height: number) => void

  aboutToAppear() {
    DevicesUtil.getStatusBarHeight(this.context).then(height => {
      this.statusBarHeight = height
      this.onHeightChange?.(height + this.navHeight) // 触发回调
    })
  }

  build() {
    Column({ space:0 }) {
      // 状态栏占位区域
      Row()
      .width('100%')
      .height(this.statusBarHeight)
      .backgroundColor(Color.Transparent)

      // 导航内容区域
      Stack(){
        Row({ space: 0 }) {
          Image($r('app.media.icon_base_back'))
            .objectFit(ImageFit.Contain)
            .width(44)
            .height(44)
            .padding(12)
            .onClick(() => router.back())

          Image($r('app.media.icon_nav_logo'))
            .objectFit(ImageFit.Contain)
            .width(64)
            .height(44)
            .padding({ right: 10 })
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)
        .backgroundColor(Color.Transparent)

        Row({ space: 0 }) {
          Text(this.parTitle)
            .fontSize(17)
            .fontColor($r('app.color.mf_base_333333'))
            .fontWeight(FontWeight.Bold)
        }
        .justifyContent(FlexAlign.Center)
        .backgroundColor(Color.Transparent)
      }
      .width('100%')
      .height(this.navHeight)
    }
    .width('100%')
    .backgroundColor(this.parBGColor)
    .expandSafeArea( [SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM] )
    .onAppear(async ()=>{
      window.getLastWindow(this.context).then(win => {
        win.setWindowLayoutFullScreen(true) // 隐藏系统栏
        // win.setWindowSystemBarEnable(['navigation']) // 可选控制导航栏显示//这一句不设置 不然第二次进入是就没状态栏那一行了
      })
    })
  }

}

示意图

3.工具

获取状态栏高度

TypeScript 复制代码
import window from '@ohos.window';
import { common } from '@kit.AbilityKit';

export class DevicesUtil {
  /// 状态栏高度
  static async getStatusBarHeight(context: common.UIAbilityContext, isVP: boolean = true): Promise<number> {
    try {
      const win = await window.getLastWindow(context);
      /*
      getWindowAvoidArea返回的物理像素,需要转换为虚拟像素返回,便于布局
      TYPE_SYSTEM:获取状态栏区域(推荐使用)
      TYPE_NAVIGATION_INDICATOR:获取导航栏区域
      TYPE_CUTOUT:获取刘海屏区域
      */
      const avoidArea = await win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
      if (isVP) {
        return DevicesUtil.pxToVp(avoidArea.topRect.height);
      } else {
        return avoidArea.topRect.height;
      }
    } catch {
      return isVP ? 24 : 96; // 默认安全高度 // 96 假设480dpi设备
    }
  }
}

4.使用示例

跳转协议

TypeScript 复制代码
/// 用户隐私协议
private userPrivacyPolicy() {
  router.pushUrl({
    url: 'pages/features/protocol/MFProtocolView',
    params: {
      webUrl: 'https://www.baidu.com',
      title: '隐私协议'
    }
  })
}

协议页面

注意:方案二会导致页面底部超出屏幕,所以需要设置.margin({bottom: this.navHeight})

TypeScript 复制代码
import { router } from '@kit.ArkUI';
import { webview } from '@kit.ArkWeb';
import { CustomNavigationBar } from '../../../support/custom/CustomNavigationBar';
import ConsoleLog from '../../../support/extension/ConsoleLog';

interface MFProtocolParams {
  webUrl: string;
  title?: string;
}

@Entry
@Component
struct MFProtocolView {
  @State webUrl: string = ''; // 接收的网页地址
  @State title: string = '详情'; // 导航栏标题
  private controller: webview.WebviewController = new webview.WebviewController();
  @State private navHeight: number = 68 // 默认值(vp)

  aboutToAppear() {
    // 在aboutToAppear生命周期中读取路由参数
    const params: MFProtocolParams = router.getParams() as MFProtocolParams;
    if (params) {
      this.webUrl = params.webUrl || 'about:blank'; // 默认为空页面
      this.title = params.title || this.title; // 默认为'协议详情'
    }
  }

  build() {
    Column() {
      // 使用自定义导航栏组件
      CustomNavigationBar({ parTitle: this.title, parBGColor: Color.Red, onHeightChange: (height)=>{
        this.navHeight = height
      }})
      // 必须传递完整WebOptions参数
      Web({
        src: this.webUrl,
        controller: this.controller
      })
        .flexGrow(1) // 自动填充剩余空间
        .margin({bottom: this.navHeight}) // 方案一不用这行代码,方案二需要这行
        .onPageBegin((event) => {
          ConsoleLog.log('开始加载:' + event.url);
        })
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Green)
    .onAppear(()=>{

    })
  }
}
相关推荐
程序员一鸣37 分钟前
鸿蒙开发:应用上架第二篇,申请发布证书
服务器·华为·harmonyos
在人间耕耘2 小时前
开发者工具箱-鸿蒙颜色转换器开发笔记
笔记·华为·harmonyos
在人间耕耘5 小时前
开发者工具箱-鸿蒙电池监控功能开发实践
华为·harmonyos
ChinaDragonDreamer7 小时前
HarmonyOS:相机选择器
harmonyos·鸿蒙
ChinaDragonDreamer7 小时前
HarmonyOS:相机管理
harmonyos·鸿蒙
鸿蒙自习室7 小时前
鸿蒙UI开发——上拉抽屉的更新与事件回调
ui·华为·harmonyos·鸿蒙
鸿蒙自习室7 小时前
鸿蒙UI开发——Builder函数的封装
ui·华为·harmonyos·鸿蒙
在人间耕耘12 小时前
开发者工具箱-鸿蒙网络工具之Ping工具开发实践
华为·harmonyos