• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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