HarmonyOS鸿蒙Next应用开发中,如何实现美观的自定义导航栏?
HarmonyOS鸿蒙Next应用开发中,如何实现美观的自定义导航栏? 在鸿蒙应用开发中,如何实现美观的自定义导航栏?
如何让状态栏颜色跟随主题动态变化?
3 回复
技术要点
- Window API状态栏设置
- 自定义导航栏组件
- @Builder组件复用
- 主题色动态应用
- 全面屏适配
完整实现代码
/**
* 自定义导航栏组件示例
*/
import { router } from '@kit.ArkUI';
import { window } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import { ThemeConstants } from '../common/ThemeConstants';
@Component
export struct CustomNavigationBar {
@Prop title: string = '';
@Prop showBackButton: boolean = true;
@Prop backgroundColor: string = '#FA8C16';
@Prop titleColor: string = '#FFFFFF';
@Prop rightText?: string;
@Prop onRightClick?: () => void;
build() {
Row() {
// 返回按钮
if (this.showBackButton) {
Image($r('app.media.ic_back'))
.width(24)
.height(24)
.fillColor(this.titleColor)
.onClick(() => {
router.back();
})
.margin({ right: 16 })
}
// 标题
Text(this.title)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor(this.titleColor)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.layoutWeight(1)
// 右侧按钮
if (this.rightText) {
Text(this.rightText)
.fontSize(16)
.fontColor(this.titleColor)
.onClick(() => {
if (this.onRightClick) {
this.onRightClick();
}
})
}
}
.width('100%')
.height(60)
.padding({ left: 20, right: 20 })
.backgroundColor(this.backgroundColor)
}
}
/**
* 页面示例 - 使用自定义导航栏
*/
@Entry
@Component
struct ExamplePage {
@State primaryColor: string = '#FA8C16';
aboutToAppear() {
this.loadThemeColor();
this.setStatusBarColor();
}
onPageShow() {
this.loadThemeColor();
this.setStatusBarColor();
}
/**
* 加载主题颜色
*/
private loadThemeColor() {
ThemeConstants.refreshTheme();
this.primaryColor = ThemeConstants.getPrimaryColor();
}
/**
* 设置状态栏颜色
*/
private async setStatusBarColor() {
try {
const context = getContext(this) as common.UIAbilityContext;
const windowClass = await window.getLastWindow(context);
if (windowClass) {
// 设置状态栏属性
await windowClass.setWindowSystemBarProperties({
statusBarContentColor: '#FFFFFF', // 状态栏文字颜色(白色)
statusBarColor: this.primaryColor // 状态栏背景色(主题色)
});
}
} catch (error) {
console.error('设置状态栏颜色失败:', JSON.stringify(error));
}
}
build() {
Column() {
// 使用自定义导航栏
CustomNavigationBar({
title: '示例页面',
showBackButton: true,
backgroundColor: this.primaryColor,
rightText: '保存',
onRightClick: () => {
console.info('点击保存');
}
})
// 页面内容
Column() {
Text('页面内容')
.fontSize(16)
}
.layoutWeight(1)
.width('100%')
.backgroundColor('#F5F5F5')
}
.width('100%')
.height('100%')
}
}
/**
* 通用导航栏Builder
*/
[@Builder](/user/Builder)
export function buildNavigationBar(
title: string,
backgroundColor: string = '#FA8C16',
showBack: boolean = true,
rightText?: string,
onRightClick?: () => void
) {
Row() {
if (showBack) {
Image($r('app.media.ic_back'))
.width(24)
.height(24)
.fillColor('#FFFFFF')
.onClick(() => router.back())
.margin({ right: 16 })
}
Text(title)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
.layoutWeight(1)
if (rightText) {
Text(rightText)
.fontSize(16)
.fontColor('#FFFFFF')
.onClick(() => {
if (onRightClick) onRightClick();
})
}
}
.width('100%')
.height(60)
.padding({ left: 20, right: 20 })
.backgroundColor(backgroundColor)
}
/**
* 状态栏工具类
*/
export class StatusBarUtil {
/**
* 设置状态栏颜色
*/
public static async setStatusBarColor(
context: common.UIAbilityContext,
backgroundColor: string,
contentColor: string = '#FFFFFF'
): Promise<void> {
try {
const windowClass = await window.getLastWindow(context);
if (windowClass) {
await windowClass.setWindowSystemBarProperties({
statusBarContentColor: contentColor,
statusBarColor: backgroundColor
});
}
} catch (error) {
console.error('设置状态栏颜色失败:', JSON.stringify(error));
}
}
/**
* 设置状态栏为透明
*/
public static async setTransparentStatusBar(
context: common.UIAbilityContext
): Promise<void> {
try {
const windowClass = await window.getLastWindow(context);
if (windowClass) {
await windowClass.setWindowSystemBarProperties({
statusBarContentColor: '#000000',
statusBarColor: '#00000000' // 透明
});
}
} catch (error) {
console.error('设置透明状态栏失败:', JSON.stringify(error));
}
}
/**
* 隐藏状态栏
*/
public static async hideStatusBar(
context: common.UIAbilityContext
): Promise<void> {
try {
const windowClass = await window.getLastWindow(context);
if (windowClass) {
await windowClass.setWindowSystemBarEnable(['navigation']);
}
} catch (error) {
console.error('隐藏状态栏失败:', JSON.stringify(error));
}
}
/**
* 显示状态栏
*/
public static async showStatusBar(
context: common.UIAbilityContext
): Promise<void> {
try {
const windowClass = await window.getLastWindow(context);
if (windowClass) {
await windowClass.setWindowSystemBarEnable(['status', 'navigation']);
}
} catch (error) {
console.error('显示状态栏失败:', JSON.stringify(error));
}
}
/**
* 设置全屏模式
*/
public static async setFullScreen(
context: common.UIAbilityContext,
isFullScreen: boolean
): Promise<void> {
try {
const windowClass = await window.getLastWindow(context);
if (windowClass) {
await windowClass.setWindowLayoutFullScreen(isFullScreen);
}
} catch (error) {
console.error('设置全屏模式失败:', JSON.stringify(error));
}
}
}
/**
* 实际项目中的导航栏示例
*/
@Entry
@Component
struct AddRecordPage {
@State primaryColor: string = '#FA8C16';
aboutToAppear() {
this.loadThemeColor();
this.setStatusBarColor();
}
private loadThemeColor() {
this.primaryColor = ThemeConstants.getPrimaryColor();
}
private async setStatusBarColor() {
const context = getContext(this) as common.UIAbilityContext;
await StatusBarUtil.setStatusBarColor(context, this.primaryColor);
}
[@Builder](/user/Builder)
buildHeader() {
Row() {
Image($r('app.media.ic_back'))
.width(24)
.height(24)
.fillColor('#FFFFFF')
.onClick(() => router.back())
Text('添加人情记录')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
.margin({ left: 16 })
Row().layoutWeight(1)
Text('保存')
.fontSize(16)
.fontColor('#FFFFFF')
.onClick(() => this.saveRecord())
}
.width('100%')
.height(60)
.padding({ left: 20, right: 20 })
.backgroundColor(this.primaryColor)
.shadow({
radius: 12,
color: 'rgba(0, 0, 0, 0.15)',
offsetX: 0,
offsetY: 4
})
}
private saveRecord() {
// 保存逻辑
}
build() {
Column() {
this.buildHeader()
// 页面内容
Scroll() {
Column() {
// 表单内容
}
.padding(16)
}
.layoutWeight(1)
}
.width('100%')
.height('100%')
}
}
核心API讲解
1. Window API - 状态栏设置
window.setWindowSystemBarProperties({
statusBarContentColor: '#FFFFFF', // 状态栏内容颜色
statusBarColor: '#FA8C16' // 状态栏背景色
})
参数说明:
statusBarContentColor: 状态栏文字和图标颜色statusBarColor: 状态栏背景颜色(支持透明)
2. 全屏模式设置
window.setWindowLayoutFullScreen(true) // 开启全屏
window.setWindowLayoutFullScreen(false) // 关闭全屏
3. 状态栏显隐控制
// 显示状态栏和导航栏
window.setWindowSystemBarEnable(['status', 'navigation'])
// 只显示导航栏(隐藏状态栏)
window.setWindowSystemBarEnable(['navigation'])
设计要点
1. 导航栏高度
.height(60) // 推荐高度60vp
2. 内边距设置
.padding({ left: 20, right: 20 }) // 左右留白20vp
3. 阴影效果
.shadow({
radius: 12,
color: 'rgba(0, 0, 0, 0.15)',
offsetX: 0,
offsetY: 4
})
4. 返回按钮
Image($r('app.media.ic_back'))
.width(24)
.height(24)
.fillColor('#FFFFFF')
.onClick(() => router.back())
最佳实践
1. 主题色动态应用
aboutToAppear() {
this.loadThemeColor();
this.setStatusBarColor();
}
onPageShow() {
this.loadThemeColor();
this.setStatusBarColor();
}
2. 使用@Builder复用
[@Builder](/user/Builder)
buildHeader() {
Row() {
// 导航栏内容
}
.backgroundColor(this.primaryColor)
}
3. 封装工具类
// 统一管理状态栏操作
StatusBarUtil.setStatusBarColor(context, color);
4. 错误处理
try {
await window.setWindowSystemBarProperties({...});
} catch (error) {
console.error('设置失败:', error);
}
适配方案
1. 全面屏适配
// 获取安全区域
const avoidArea = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
const topHeight = avoidArea.topRect.height;
// 添加顶部padding
.padding({ top: topHeight })
2. 不同设备适配
// 根据设备类型调整高度
const navBarHeight = deviceType === 'tablet' ? 70 : 60;
3. 横屏适配
// 监听屏幕旋转
windowClass.on('windowSizeChange', (size) => {
// 调整布局
});
使用场景
- 普通页面: 标题+返回按钮
- 表单页面: 标题+取消+保存
- 详情页面: 标题+返回+更多操作
- 搜索页面: 搜索框+取消
- 沉浸式页面: 透明状态栏
避坑指南
1. ❌ 忘记在onPageShow中刷新
// 错误: 只在aboutToAppear中设置
aboutToAppear() {
this.setStatusBarColor();
}
// 正确: 同时在onPageShow中设置
onPageShow() {
this.setStatusBarColor();
}
2. ❌ 状态栏颜色不跟随主题
// 错误: 硬编码颜色
.backgroundColor('#FA8C16')
// 正确: 使用主题色
.backgroundColor(this.primaryColor)
3. ❌ 异步操作未处理
// 正确: 使用async/await
private async setStatusBarColor() {
await window.setWindowSystemBarProperties({...});
}
效果展示
- 状态栏颜色与导航栏一致
- 支持主题动态切换
- 返回按钮交互流畅
- 阴影效果美观
- 全面屏完美适配
总结
本文提供了完整的导航栏和状态栏解决方案:
- ✅ 自定义导航栏组件
- ✅ 状态栏动态设置
- ✅ 主题色自动适配
- ✅ 全面屏完美适配
- ✅ 工具类封装复用
更多关于HarmonyOS鸿蒙Next应用开发中,如何实现美观的自定义导航栏?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
鸿蒙Next自定义导航栏主要通过以下方式实现:
- 使用Navigation组件作为基础容器
- 通过@CustomDialog装饰器创建自定义导航栏组件
- 在Navigation的title属性中嵌入自定义布局
- 利用Row/Column容器结合Text、Image等基础组件构建导航栏UI
- 通过状态变量管理导航栏的交互状态
- 使用资源文件管理颜色、尺寸等样式属性
关键代码结构示例:
Navigation() {
// 页面内容
}
.title({
Builder: this.CustomTitleBuilder
})
导航栏高度可通过系统API获取,建议遵循鸿蒙设计规范中的推荐尺寸。
在HarmonyOS Next应用开发中,实现美观且动态的自定义导航栏,核心在于使用Window和UI上下文进行灵活控制。
1. 实现自定义导航栏
关键在于隐藏默认导航栏,并使用自定义组件替代。
- 隐藏系统导航栏:在
EntryAbility的onWindowStageCreate方法中,通过Window对象设置。import { window } from '@kit.ArkUI'; onWindowStageCreate(windowStage: window.WindowStage): void { // 获取主窗口 let mainWindow = windowStage.getMainWindow(); // 隐藏系统导航栏 mainWindow.setWindowSystemBarEnable(['navigation']); // 传入空数组即可完全隐藏 // ... 其他初始化代码 } - 构建自定义组件:在ArkUI页面中,使用
Row、Column、Text、Image等基础组件在页面顶部自由组合导航栏布局、图标和标题,并为其设置样式和事件。@Component struct CustomNavBar { build() { Row() { Image($r('app.media.back')) // 返回图标 .onClick(() => { // 处理返回事件 }) Text('页面标题') .fontSize(20) .fontWeight(FontWeight.Medium) } .width('100%') .height(50) .padding({ left: 12, right: 12 }) .backgroundColor(Color.White) .justifyContent(FontAlign.SpaceBetween) } } - 集成到页面:在页面的
build方法中,将自定义导航栏组件置于顶部。@Entry @Component struct Index { build() { Column() { CustomNavBar() // 自定义导航栏 // 页面主要内容... Scroll() { // ... } } .width('100%') .height('100%') } }
2. 状态栏颜色动态跟随主题
HarmonyOS Next提供了完整的动态主题能力,可通过UI上下文(UIContext)获取并响应主题变化。
- 获取当前主题色:使用资源管理器和
UI上下文获取当前的主题颜色资源,特别是状态栏背景常用的$color('sys.color.ohos_id_color_sub_background')。 - 应用主题色:将获取到的颜色资源设置为自定义导航栏(或状态栏区域)的背景色。
- 监听主题变化:在自定义组件或页面中监听主题变化事件,并在回调中更新颜色。
示例代码片段:
import { common } from '@kit.ArkUI';
@Entry
@Component
struct Index {
// 通过UI上下文监听主题变化
private uiContext: common.UIContext = getContext(this) as common.UIContext;
@State navBarColor: Resource = $color('sys.color.ohos_id_color_sub_background'); // 初始颜色
aboutToAppear(): void {
// 监听主题变化
this.uiContext.on('themeChange', () => {
// 主题变更时,更新颜色状态
this.navBarColor = $color('sys.color.ohos_id_color_sub_background');
});
}
build() {
Column() {
// 自定义导航栏,背景色绑定到动态状态变量
Row() {
// ... 导航栏内容
}
.width('100%')
.height(50)
.backgroundColor(this.navBarColor) // 动态应用颜色
// ... 页面其他内容
}
}
}
关键点总结
- 窗口控制:使用
WindowAPI管理系统栏显示。 - 组件化:将导航栏封装为可复用的自定义组件。
- 主题响应:通过
UIContext的themeChange事件和系统颜色资源($color('sys.color...'))实现颜色动态切换。 - 样式与交互:结合ArkUI的声明式语法和响应式状态管理,为导航栏添加丰富的样式和流畅的交互逻辑。
通过以上步骤,你可以创建出既美观又能无缝适配系统深色/浅色模式的自定义导航栏。

