1# 窗口标题栏定制开发指导(ArkTS) 2 3## 概述 4 5### 功能简介 6 7窗口标题栏是图形用户界面中的一个重要元素,它位于窗口的顶部,通常包含了窗口的标题以及一些控制按钮。标题栏的主要作用是提供关于窗口的基本信息,同时也为用户提供了一些控制选项。OpenHarmony有默认的窗口标题栏样式,本文基于ArkTS语言,提供窗口标题栏自定义方法。 8 9### 约束与限制 10 11需要在`foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/container_modal/interfaces`路径下加入有自定义标题栏代码的js文件。并且在`foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/container_modal/interfaces/BUILD.gn`中配置js文件编译成abc文件,最后在`foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/BUILD.gn`完成编译配置。 12 13## 开发步骤 14 15以默认的系统标题栏为例,定制窗口标题栏的开发步骤如下: 16 171. 使用ArkTS语言编写定制的窗口标题栏。 18 ```ts 19 import image from '@ohos.multimedia.image'; 20 21 const TITLE_ICON_SIZE: string = '20vp' 22 const TITLE_PADDING_START: string = '20vp' 23 const TITLE_ELEMENT_MARGIN_HORIZONTAL: string = '12vp' 24 const TITLE_TEXT_FONT_SIZE: string = '16fp' 25 const TITLE_TEXT_FONT_WEIGHT: string = '500px' 26 const TITLE_ROW_HEIGHT: string = '37vp' 27 28 @Entry 29 @Component 30 struct Index { 31 @State appLabel: string = ''; 32 @State appLabelColor: Color = 0xff000000; 33 @State appIcon: PixelMap | undefined = undefined; 34 35 // 1、重写失焦和获焦函数,用于改变字体颜色 36 onWindowFocused() { 37 this.appLabelColor = 0xff000000; 38 } 39 40 onWindowUnfocused() { 41 this.appLabelColor = 0x66000000; 42 } 43 44 // 2、重写标题栏设置应用图标和名称的方法 45 setAppTitle(content: string ) { 46 this.appLabel = content; 47 } 48 49 setAppIcon(pixelMap: image.PixelMap) { 50 this.appIcon = pixelMap; 51 } 52 53 build() { 54 Row() { 55 // 3、Image组件用于显示应用图标 56 Image(this.appIcon) 57 .id("enhanceAppIcon") 58 .height(TITLE_ICON_SIZE) 59 .width(TITLE_ICON_SIZE) 60 .interpolation(ImageInterpolation.Medium) 61 .focusable(false) 62 .margin({ left: TITLE_PADDING_START, right: TITLE_ELEMENT_MARGIN_HORIZONTAL }) 63 // 4、Text组件用于显示应用名称 64 Text(this.appLabel) 65 .id("enhanceAppLabel") 66 .fontSize(TITLE_TEXT_FONT_SIZE) 67 .fontColor(this.appLabelColor) 68 .fontWeight(TITLE_TEXT_FONT_WEIGHT) 69 .maxLines(1) 70 .textOverflow({ overflow: TextOverflow.Ellipsis }) 71 .textAlign(TextAlign.Start) 72 .layoutWeight(1.0) 73 } 74 .width('100%') 75 .height(TITLE_ROW_HEIGHT) 76 .justifyContent(FlexAlign.Start) 77 .alignItems(VerticalAlign.Center) 78 .padding({ top: 6, bottom: 6 }) 79 } 80 } 81 ``` 822. 将ets文件编译成js文件。 83 ```js 84 const TITLE_ICON_SIZE = '20vp'; 85 const TITLE_PADDING_START = '20vp'; 86 const TITLE_ELEMENT_MARGIN_HORIZONTAL = '12vp'; 87 const TITLE_TEXT_FONT_SIZE = '16fp'; 88 const TITLE_TEXT_FONT_WEIGHT = '500px'; 89 const TITLE_ROW_HEIGHT = '37vp' 90 export class Index extends ViewPU { 91 constructor(parent, params, __localStorage, elmtId = -1) { 92 super(parent, __localStorage, elmtId); 93 this.__appLabel = new ObservedPropertySimplePU('', this, "appLabel"); 94 this.__textColor = new ObservedPropertySimplePU(0xff000000, this, "textColor"); 95 this.__pixelMap = new ObservedPropertyObjectPU(undefined, this, "appIcon"); 96 this.setInitiallyProvidedValue(params); 97 } 98 setInitiallyProvidedValue(params) { 99 if (params.textColor !== undefined) { 100 this.textColor = params.textColor; 101 } 102 if (params.appLabel !== undefined) { 103 this.appLabel = params.appLabel; 104 } 105 if (params.appIcon !== undefined) { 106 this.appIcon = params.appIcon; 107 } 108 } 109 updateStateVars(params) { 110 } 111 purgeVariableDependenciesOnElmtId(rmElmtId) { 112 this.__textColor.purgeDependencyOnElmtId(rmElmtId); 113 this.__appLabel.purgeDependencyOnElmtId(rmElmtId); 114 this.__appIcon.purgeDependencyOnElmtId(rmElmtId); 115 } 116 aboutToBeDeleted() { 117 this.__textColor.aboutToBeDeleted(); 118 this.__appLabel.aboutToBeDeleted(); 119 this.__appIcon.aboutToBeDeleted(); 120 SubscriberManager.Get().delete(this.id__()); 121 this.aboutToBeDeletedInternal(); 122 } 123 get textColor() { 124 return this.__textColor.get(); 125 } 126 set textColor(newValue) { 127 this.__textColor.set(newValue); 128 } 129 get appLabel() { 130 return this.__appLabel.get(); 131 } 132 set appLabel(newValue) { 133 this.__appLabel.set(newValue); 134 } 135 get appIcon() { 136 return this.__appIcon.get(); 137 } 138 set appIcon(newValue) { 139 this.__appIcon.set(newValue); 140 } 141 onWindowFocused() { 142 this.textColor = 0xff000000; 143 } 144 onWindowUnfocused() { 145 this.textColor = 0x66000000; 146 } 147 setAppTitle(content) { 148 this.appLabel = content; 149 } 150 setAppIcon(pixelMap) { 151 this.appIcon = pixelMap; 152 } 153 initialRender() { 154 this.observeComponentCreation((elmtId, isInitialRender) => { 155 ViewStackProcessor.StartGetAccessRecordingFor(elmtId); 156 Row.create(); 157 Row.width('100%'); 158 Row.height(TITLE_ROW_HEIGHT); 159 Row.justifyContent(FlexAlign.Start); 160 Row.alignItems(VerticalAlign.Center); 161 Row.padding({ top: 6, bottom: 6 }); 162 if (!isInitialRender) { 163 Row.pop(); 164 } 165 ViewStackProcessor.StopGetAccessRecording(); 166 }); 167 this.observeComponentCreation((elmtId, isInitialRender) => { 168 ViewStackProcessor.StartGetAccessRecordingFor(elmtId); 169 Image.create(this.appIcon); 170 Image.id("enhanceAppIcon"); 171 Image.height(TITLE_ICON_SIZE); 172 Image.width(TITLE_ICON_SIZE); 173 Image.interpolation(ImageInterpolation.Medium); 174 Image.focusable(false); 175 Image.margin({ left: TITLE_PADDING_START, right: TITLE_ELEMENT_MARGIN_HORIZONTAL }); 176 if (!isInitialRender) { 177 Image.pop(); 178 } 179 ViewStackProcessor.StopGetAccessRecording(); 180 }); 181 this.observeComponentCreation((elmtId, isInitialRender) => { 182 ViewStackProcessor.StartGetAccessRecordingFor(elmtId); 183 Text.create(this.appLabel); 184 Image.id("enhanceAppLabel"); 185 Text.maxLines(1); 186 Text.fontSize(TITLE_TEXT_FONT_SIZE); 187 Text.fontColor(this.textColor); 188 Text.fontWeight(TITLE_TEXT_FONT_WEIGHT); 189 Text.textOverflow({ overflow: TextOverflow.Ellipsis }); 190 Text.textAlign(TextAlign.Start); 191 Text.layoutWeight(1.0); 192 if (!isInitialRender) { 193 Text.pop(); 194 } 195 ViewStackProcessor.StopGetAccessRecording(); 196 }); 197 Text.pop(); 198 Row.pop(); 199 } 200 rerender() { 201 this.updateDirtyElements(); 202 } 203 } 204 ViewStackProcessor.StartGetAccessRecordingFor(ViewStackProcessor.AllocateNewElmetIdForNextComponent()); 205 // loadDocument方法需要更改为loadCustomTitleBar 206 loadCustomTitleBar(new Index(undefined, {})); 207 ViewStackProcessor.StopGetAccessRecording(); 208 ``` 209 - DevEco Studio编译生成的js文件或ts文件一般在工程的如下目录下:build/default/cache/default/default@CompileArkTS/esmodule/debug/entry/src/main/ets/pages/。 210 - 处理ts文件,使其符合js语法规范。 211 - js文件中的loadDocument或registerNameRouter方法需要更改使用loadCustomTitleBar方法。 212 ```js 213 loadCustomTitleBar(new Index(undefined, {})); 214 ``` 215 2163. 通过BUILD.gn文件将处理后的js文件加入系统编译依赖,进一步生成.abc文件。 217 ``` 218 import("//arkcompiler/ets_frontend/es2panda/es2abc_config.gni") 219 220 es2abc_gen_abc("gen_customtitle_abc") { 221 src_js = rebase_path("customtitle.js") 222 dst_file = rebase_path(target_out_dir + "/customtitle.abc") 223 in_puts = [ "customtitle.js" ] 224 out_puts = [ target_out_dir + "/customtitle.abc" ] 225 extra_args = [ "--module" ] 226 } 227 ``` 228 将上述gen_customtitle_abc加入到`foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/BUILD.gn`文件的编译依赖中。编译后生成的.abc文件在`obj/foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/container_modal/interfaces`目录下。 229 230 具体可参考如下路径下的实现:[foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/container_modal/interfaces](https://gitee.com/openharmony/arkui_ace_engine/tree/master/frameworks/core/components_ng/pattern/container_modal/interfaces)。 231 232 2334. 将.abc文件配置到系统中的指定目录,如/system/lib64/,然后命令行设置配置参数"persist.sys.arkui.customtitle"的值为.abc文件的路径,就可以读取并显示自定义的标题栏。 234 235 ``` 236 hdc shell param set persist.sys.arkui.customtitle /system/lib64/customtitle.abc 237 ``` 238