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