1e41f4b71Sopenharmony_ci# Window Title Bar Customization Development (ArkTS) 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## Overview 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci### Introduction 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciAs a crucial element of the GUI, the window title bar is located at the top of a window. It is intended to help users identify the purpose or content of the window, complete with some handy control options. OpenHarmony provides a default window title bar. You can customize it to match your needs. This topic provides guidance on customizing your title bar in ArkTS. 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci### Constraints 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ciThe .js files that contain the custom title bar code must be placed in **foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/container_modal/interfaces**. 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ciThe JS files must be built into ABC files with the **foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/container_modal/interfaces/BUILD.gn** file. 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ciThe build configuration must be specified in **foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/BUILD.gn**. 16e41f4b71Sopenharmony_ci 17e41f4b71Sopenharmony_ci## How to Develop 18e41f4b71Sopenharmony_ci 19e41f4b71Sopenharmony_ciIn this example, a custom system title bar is developed. 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ci1. Write the following code in an .ets file. 22e41f4b71Sopenharmony_ci ```ts 23e41f4b71Sopenharmony_ci import image from '@ohos.multimedia.image'; 24e41f4b71Sopenharmony_ci 25e41f4b71Sopenharmony_ci const TITLE_ICON_SIZE: string = '20vp' 26e41f4b71Sopenharmony_ci const TITLE_PADDING_START: string = '20vp' 27e41f4b71Sopenharmony_ci const TITLE_ELEMENT_MARGIN_HORIZONTAL: string = '12vp' 28e41f4b71Sopenharmony_ci const TITLE_TEXT_FONT_SIZE: string = '16fp' 29e41f4b71Sopenharmony_ci const TITLE_TEXT_FONT_WEIGHT: string = '500px' 30e41f4b71Sopenharmony_ci const TITLE_ROW_HEIGHT: string = '37vp' 31e41f4b71Sopenharmony_ci 32e41f4b71Sopenharmony_ci @Entry 33e41f4b71Sopenharmony_ci @Component 34e41f4b71Sopenharmony_ci struct Index { 35e41f4b71Sopenharmony_ci @State appLabel: string = ''; 36e41f4b71Sopenharmony_ci @State appLabelColor: Color = 0xff000000; 37e41f4b71Sopenharmony_ci @State appIcon: PixelMap | undefined = undefined; 38e41f4b71Sopenharmony_ci 39e41f4b71Sopenharmony_ci // 1. Override the following methods to change the font color when the window obtains or loses focus. 40e41f4b71Sopenharmony_ci onWindowFocused() { 41e41f4b71Sopenharmony_ci this.appLabelColor = 0xff000000; 42e41f4b71Sopenharmony_ci } 43e41f4b71Sopenharmony_ci 44e41f4b71Sopenharmony_ci onWindowUnfocused() { 45e41f4b71Sopenharmony_ci this.appLabelColor = 0x66000000; 46e41f4b71Sopenharmony_ci } 47e41f4b71Sopenharmony_ci 48e41f4b71Sopenharmony_ci // 2. Override the following methods for setting the application icon and name on the title bar. 49e41f4b71Sopenharmony_ci setAppTitle(content: string ) { 50e41f4b71Sopenharmony_ci this.appLabel = content; 51e41f4b71Sopenharmony_ci } 52e41f4b71Sopenharmony_ci 53e41f4b71Sopenharmony_ci setAppIcon(pixelMap: image.PixelMap) { 54e41f4b71Sopenharmony_ci this.appIcon = pixelMap; 55e41f4b71Sopenharmony_ci } 56e41f4b71Sopenharmony_ci 57e41f4b71Sopenharmony_ci build() { 58e41f4b71Sopenharmony_ci Row() { 59e41f4b71Sopenharmony_ci // 3. Create an <Image> component for showing the application icon. 60e41f4b71Sopenharmony_ci Image(this.appIcon) 61e41f4b71Sopenharmony_ci .id("enhanceAppIcon") 62e41f4b71Sopenharmony_ci .height(TITLE_ICON_SIZE) 63e41f4b71Sopenharmony_ci .width(TITLE_ICON_SIZE) 64e41f4b71Sopenharmony_ci .interpolation(ImageInterpolation.Medium) 65e41f4b71Sopenharmony_ci .focusable(false) 66e41f4b71Sopenharmony_ci .margin({ left: TITLE_PADDING_START, right: TITLE_ELEMENT_MARGIN_HORIZONTAL }) 67e41f4b71Sopenharmony_ci // 4. Create a <Text> component for showing the application name. 68e41f4b71Sopenharmony_ci Text(this.appLabel) 69e41f4b71Sopenharmony_ci .id("enhanceAppLabel") 70e41f4b71Sopenharmony_ci .fontSize(TITLE_TEXT_FONT_SIZE) 71e41f4b71Sopenharmony_ci .fontColor(this.appLabelColor) 72e41f4b71Sopenharmony_ci .fontWeight(TITLE_TEXT_FONT_WEIGHT) 73e41f4b71Sopenharmony_ci .maxLines(1) 74e41f4b71Sopenharmony_ci .textOverflow({ overflow: TextOverflow.Ellipsis }) 75e41f4b71Sopenharmony_ci .textAlign(TextAlign.Start) 76e41f4b71Sopenharmony_ci .layoutWeight(1.0) 77e41f4b71Sopenharmony_ci } 78e41f4b71Sopenharmony_ci .width('100%') 79e41f4b71Sopenharmony_ci .height(TITLE_ROW_HEIGHT) 80e41f4b71Sopenharmony_ci .justifyContent(FlexAlign.Start) 81e41f4b71Sopenharmony_ci .alignItems(VerticalAlign.Center) 82e41f4b71Sopenharmony_ci .padding({ top: 6, bottom: 6 }) 83e41f4b71Sopenharmony_ci } 84e41f4b71Sopenharmony_ci } 85e41f4b71Sopenharmony_ci ``` 86e41f4b71Sopenharmony_ci2. Compile the .ets file into a .js file. 87e41f4b71Sopenharmony_ci ```js 88e41f4b71Sopenharmony_ci const TITLE_ICON_SIZE = '20vp'; 89e41f4b71Sopenharmony_ci const TITLE_PADDING_START = '20vp'; 90e41f4b71Sopenharmony_ci const TITLE_ELEMENT_MARGIN_HORIZONTAL = '12vp'; 91e41f4b71Sopenharmony_ci const TITLE_TEXT_FONT_SIZE = '16fp'; 92e41f4b71Sopenharmony_ci const TITLE_TEXT_FONT_WEIGHT = '500px'; 93e41f4b71Sopenharmony_ci const TITLE_ROW_HEIGHT = '37vp' 94e41f4b71Sopenharmony_ci export class Index extends ViewPU { 95e41f4b71Sopenharmony_ci constructor(parent, params, __localStorage, elmtId = -1) { 96e41f4b71Sopenharmony_ci super(parent, __localStorage, elmtId); 97e41f4b71Sopenharmony_ci this.__appLabel = new ObservedPropertySimplePU('', this, "appLabel"); 98e41f4b71Sopenharmony_ci this.__textColor = new ObservedPropertySimplePU(0xff000000, this, "textColor"); 99e41f4b71Sopenharmony_ci this.__pixelMap = new ObservedPropertyObjectPU(undefined, this, "appIcon"); 100e41f4b71Sopenharmony_ci this.setInitiallyProvidedValue(params); 101e41f4b71Sopenharmony_ci } 102e41f4b71Sopenharmony_ci setInitiallyProvidedValue(params) { 103e41f4b71Sopenharmony_ci if (params.textColor !== undefined) { 104e41f4b71Sopenharmony_ci this.textColor = params.textColor; 105e41f4b71Sopenharmony_ci } 106e41f4b71Sopenharmony_ci if (params.appLabel !== undefined) { 107e41f4b71Sopenharmony_ci this.appLabel = params.appLabel; 108e41f4b71Sopenharmony_ci } 109e41f4b71Sopenharmony_ci if (params.appIcon !== undefined) { 110e41f4b71Sopenharmony_ci this.appIcon = params.appIcon; 111e41f4b71Sopenharmony_ci } 112e41f4b71Sopenharmony_ci } 113e41f4b71Sopenharmony_ci updateStateVars(params) { 114e41f4b71Sopenharmony_ci } 115e41f4b71Sopenharmony_ci purgeVariableDependenciesOnElmtId(rmElmtId) { 116e41f4b71Sopenharmony_ci this.__textColor.purgeDependencyOnElmtId(rmElmtId); 117e41f4b71Sopenharmony_ci this.__appLabel.purgeDependencyOnElmtId(rmElmtId); 118e41f4b71Sopenharmony_ci this.__appIcon.purgeDependencyOnElmtId(rmElmtId); 119e41f4b71Sopenharmony_ci } 120e41f4b71Sopenharmony_ci aboutToBeDeleted() { 121e41f4b71Sopenharmony_ci this.__textColor.aboutToBeDeleted(); 122e41f4b71Sopenharmony_ci this.__appLabel.aboutToBeDeleted(); 123e41f4b71Sopenharmony_ci this.__appIcon.aboutToBeDeleted(); 124e41f4b71Sopenharmony_ci SubscriberManager.Get().delete(this.id__()); 125e41f4b71Sopenharmony_ci this.aboutToBeDeletedInternal(); 126e41f4b71Sopenharmony_ci } 127e41f4b71Sopenharmony_ci get textColor() { 128e41f4b71Sopenharmony_ci return this.__textColor.get(); 129e41f4b71Sopenharmony_ci } 130e41f4b71Sopenharmony_ci set textColor(newValue) { 131e41f4b71Sopenharmony_ci this.__textColor.set(newValue); 132e41f4b71Sopenharmony_ci } 133e41f4b71Sopenharmony_ci get appLabel() { 134e41f4b71Sopenharmony_ci return this.__appLabel.get(); 135e41f4b71Sopenharmony_ci } 136e41f4b71Sopenharmony_ci set appLabel(newValue) { 137e41f4b71Sopenharmony_ci this.__appLabel.set(newValue); 138e41f4b71Sopenharmony_ci } 139e41f4b71Sopenharmony_ci get appIcon() { 140e41f4b71Sopenharmony_ci return this.__appIcon.get(); 141e41f4b71Sopenharmony_ci } 142e41f4b71Sopenharmony_ci set appIcon(newValue) { 143e41f4b71Sopenharmony_ci this.__appIcon.set(newValue); 144e41f4b71Sopenharmony_ci } 145e41f4b71Sopenharmony_ci onWindowFocused() { 146e41f4b71Sopenharmony_ci this.textColor = 0xff000000; 147e41f4b71Sopenharmony_ci } 148e41f4b71Sopenharmony_ci onWindowUnfocused() { 149e41f4b71Sopenharmony_ci this.textColor = 0x66000000; 150e41f4b71Sopenharmony_ci } 151e41f4b71Sopenharmony_ci setAppTitle(content) { 152e41f4b71Sopenharmony_ci this.appLabel = content; 153e41f4b71Sopenharmony_ci } 154e41f4b71Sopenharmony_ci setAppIcon(pixelMap) { 155e41f4b71Sopenharmony_ci this.appIcon = pixelMap; 156e41f4b71Sopenharmony_ci } 157e41f4b71Sopenharmony_ci initialRender() { 158e41f4b71Sopenharmony_ci this.observeComponentCreation((elmtId, isInitialRender) => { 159e41f4b71Sopenharmony_ci ViewStackProcessor.StartGetAccessRecordingFor(elmtId); 160e41f4b71Sopenharmony_ci Row.create(); 161e41f4b71Sopenharmony_ci Row.width('100%'); 162e41f4b71Sopenharmony_ci Row.height(TITLE_ROW_HEIGHT); 163e41f4b71Sopenharmony_ci Row.justifyContent(FlexAlign.Start); 164e41f4b71Sopenharmony_ci Row.alignItems(VerticalAlign.Center); 165e41f4b71Sopenharmony_ci Row.padding({ top: 6, bottom: 6 }); 166e41f4b71Sopenharmony_ci if (!isInitialRender) { 167e41f4b71Sopenharmony_ci Row.pop(); 168e41f4b71Sopenharmony_ci } 169e41f4b71Sopenharmony_ci ViewStackProcessor.StopGetAccessRecording(); 170e41f4b71Sopenharmony_ci }); 171e41f4b71Sopenharmony_ci this.observeComponentCreation((elmtId, isInitialRender) => { 172e41f4b71Sopenharmony_ci ViewStackProcessor.StartGetAccessRecordingFor(elmtId); 173e41f4b71Sopenharmony_ci Image.create(this.appIcon); 174e41f4b71Sopenharmony_ci Image.id("enhanceAppIcon"); 175e41f4b71Sopenharmony_ci Image.height(TITLE_ICON_SIZE); 176e41f4b71Sopenharmony_ci Image.width(TITLE_ICON_SIZE); 177e41f4b71Sopenharmony_ci Image.interpolation(ImageInterpolation.Medium); 178e41f4b71Sopenharmony_ci Image.focusable(false); 179e41f4b71Sopenharmony_ci Image.margin({ left: TITLE_PADDING_START, right: TITLE_ELEMENT_MARGIN_HORIZONTAL }); 180e41f4b71Sopenharmony_ci if (!isInitialRender) { 181e41f4b71Sopenharmony_ci Image.pop(); 182e41f4b71Sopenharmony_ci } 183e41f4b71Sopenharmony_ci ViewStackProcessor.StopGetAccessRecording(); 184e41f4b71Sopenharmony_ci }); 185e41f4b71Sopenharmony_ci this.observeComponentCreation((elmtId, isInitialRender) => { 186e41f4b71Sopenharmony_ci ViewStackProcessor.StartGetAccessRecordingFor(elmtId); 187e41f4b71Sopenharmony_ci Text.create(this.appLabel); 188e41f4b71Sopenharmony_ci Image.id("enhanceAppLabel"); 189e41f4b71Sopenharmony_ci Text.maxLines(1); 190e41f4b71Sopenharmony_ci Text.fontSize(TITLE_TEXT_FONT_SIZE); 191e41f4b71Sopenharmony_ci Text.fontColor(this.textColor); 192e41f4b71Sopenharmony_ci Text.fontWeight(TITLE_TEXT_FONT_WEIGHT); 193e41f4b71Sopenharmony_ci Text.textOverflow({ overflow: TextOverflow.Ellipsis }); 194e41f4b71Sopenharmony_ci Text.textAlign(TextAlign.Start); 195e41f4b71Sopenharmony_ci Text.layoutWeight(1.0); 196e41f4b71Sopenharmony_ci if (!isInitialRender) { 197e41f4b71Sopenharmony_ci Text.pop(); 198e41f4b71Sopenharmony_ci } 199e41f4b71Sopenharmony_ci ViewStackProcessor.StopGetAccessRecording(); 200e41f4b71Sopenharmony_ci }); 201e41f4b71Sopenharmony_ci Text.pop(); 202e41f4b71Sopenharmony_ci Row.pop(); 203e41f4b71Sopenharmony_ci } 204e41f4b71Sopenharmony_ci rerender() { 205e41f4b71Sopenharmony_ci this.updateDirtyElements(); 206e41f4b71Sopenharmony_ci } 207e41f4b71Sopenharmony_ci } 208e41f4b71Sopenharmony_ci ViewStackProcessor.StartGetAccessRecordingFor(ViewStackProcessor.AllocateNewElmetIdForNextComponent()); 209e41f4b71Sopenharmony_ci // The loadDocument method needs to be changed to loadCustomTitleBar. 210e41f4b71Sopenharmony_ci loadCustomTitleBar(new Index(undefined, {})); 211e41f4b71Sopenharmony_ci ViewStackProcessor.StopGetAccessRecording(); 212e41f4b71Sopenharmony_ci ``` 213e41f4b71Sopenharmony_ci - In general cases, the .js or .ts (.ets) files generated in DevEco Studio are stored in the **build/default/cache/default/default@CompileArkTS/esmodule/debug/entry/src/main/ets/pages/** directory of the project. 214e41f4b71Sopenharmony_ci - Process the .ets file so that it complies with the JS syntax specifications. 215e41f4b71Sopenharmony_ci - The **loadDocument** or **registerNameRouter** method in the .js file must be be changed to **loadCustomTitleBar**. 216e41f4b71Sopenharmony_ci ```js 217e41f4b71Sopenharmony_ci loadCustomTitleBar(new Index(undefined, {})); 218e41f4b71Sopenharmony_ci ``` 219e41f4b71Sopenharmony_ci 220e41f4b71Sopenharmony_ci3. Use the **BUILD.gn** file to add the .js file as a system build dependency to generate an .abc file. 221e41f4b71Sopenharmony_ci ``` 222e41f4b71Sopenharmony_ci import("//arkcompiler/ets_frontend/es2panda/es2abc_config.gni") 223e41f4b71Sopenharmony_ci 224e41f4b71Sopenharmony_ci es2abc_gen_abc("gen_customtitle_abc") { 225e41f4b71Sopenharmony_ci src_js = rebase_path("customtitle.js") 226e41f4b71Sopenharmony_ci dst_file = rebase_path(target_out_dir + "/customtitle.abc") 227e41f4b71Sopenharmony_ci in_puts = [ "customtitle.js" ] 228e41f4b71Sopenharmony_ci out_puts = [ target_out_dir + "/customtitle.abc" ] 229e41f4b71Sopenharmony_ci extra_args = [ "--module" ] 230e41f4b71Sopenharmony_ci } 231e41f4b71Sopenharmony_ci ``` 232e41f4b71Sopenharmony_ci Add **gen_customtitle_abc** to the build dependencies in the **foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/BUILD.gn** file. The .abc file generated after compilation is stored in the **obj/foundation/arkui/ace_engine/frameworks/core/components_ng/pattern/container_modal/interfaces** directory. 233e41f4b71Sopenharmony_ci 234e41f4b71Sopenharmony_ci For details, see the implementation in [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). 235e41f4b71Sopenharmony_ci 236e41f4b71Sopenharmony_ci 237e41f4b71Sopenharmony_ci4. Add the .abc file to a specific directory in the system, for example, **/system/lib64/**, and run the following command to set **persist.sys.arkui.customtitle** to the path of the .abc file so that the custom title bar can be read and displayed properly. 238e41f4b71Sopenharmony_ci 239e41f4b71Sopenharmony_ci ``` 240e41f4b71Sopenharmony_ci hdc shell param set persist.sys.arkui.customtitle /system/lib64/customtitle.abc 241e41f4b71Sopenharmony_ci ``` 242