• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Managing Overlays (OverlayManager)
2
3Overlays, implemented using **OverlayManager**, are used to display custom UI content on top of a page, but below such components as created through **Dialog**, **Popup**, **Menu**, **BindSheet**, **BindContentCover**, and **Toast**. These overlays are confined to the safe area of the current window. Overlays are applicable to scenarios such as persistent floating elements.
4
5![image](figures/overlayManager.png)
6
7You can use the [getOverlayManager](../reference/apis-arkui/js-apis-arkui-UIContext.md#getoverlaymanager12) API in [UIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md#uicontext) to obtain the [OverlayManager](../reference/apis-arkui/js-apis-arkui-UIContext.md#overlaymanager12) object associated with the current UI context, and then call the corresponding APIs using this object.
8
9## Specifications Constraints
10
11* The nodes on **OverlayManager** are above the page level, but below such components as created through **Dialog**, **Popup**, **Menu**, **BindSheet**, **BindContentCover**, and **Toast**.
12* There is no default animation when nodes on **OverlayManager** appear or disappear.
13* The drawing method inside and outside the safe area of nodes on **OverlayManager** is consistent with that of the page, and the keyboard avoidance method is also the same as that of the page.
14* For properties related to **OverlayManager**, you are advised to use AppStorage for global storage across the application to prevent changes in property values when switching pages, which could lead to service errors.
15
16## Managing Overlays
17
18With **OverlayManager**, you can add a specified node ([addComponentContent](../reference/apis-arkui/js-apis-arkui-UIContext.md#addcomponentcontent12)), remove a specified node ([removeComponentContent](../reference/apis-arkui/js-apis-arkui-UIContext.md#removecomponentcontent12)), show all nodes ([showAllComponentContents](../reference/apis-arkui/js-apis-arkui-UIContext.md#showallcomponentcontents12)), and hide all nodes ([hideAllComponentContents](../reference/apis-arkui/js-apis-arkui-UIContext.md#hideallcomponentcontents12)).
19
20```ts
21import { ComponentContent, OverlayManager, router } from '@kit.ArkUI';
22
23class Params {
24  text: string = ""
25  offset: Position
26  constructor(text: string, offset: Position) {
27    this.text = text
28    this.offset = offset
29  }
30}
31@Builder
32function builderText(params: Params) {
33  Column() {
34    Text(params.text)
35      .fontSize(30)
36      .fontWeight(FontWeight.Bold)
37  }.offset(params.offset)
38}
39
40@Entry
41@Component
42struct OverlayExample {
43  @State message: string = 'ComponentContent';
44  private uiContext: UIContext = this.getUIContext()
45  private overlayNode: OverlayManager = this.uiContext.getOverlayManager()
46  @StorageLink('contentArray') contentArray: ComponentContent<Params>[] = []
47  @StorageLink('componentContentIndex') componentContentIndex: number = 0
48  @StorageLink('arrayIndex') arrayIndex: number = 0
49  @StorageLink("componentOffset") componentOffset: Position = {x: 0, y: 80}
50
51  build() {
52    Column({space:10}) {
53      Button("Increment componentContentIndex: " + this.componentContentIndex).onClick(()=>{
54        ++this.componentContentIndex
55      })
56      Button("Decrement componentContentIndex: " + this.componentContentIndex).onClick(()=>{
57        --this.componentContentIndex
58      })
59      Button("Add ComponentContent" + this.contentArray.length).onClick(()=>{
60        let componentContent = new ComponentContent(
61          this.uiContext, wrapBuilder<[Params]>(builderText),
62          new Params(this.message + (this.contentArray.length), this.componentOffset)
63        )
64        this.contentArray.push(componentContent)
65        this.overlayNode.addComponentContent(componentContent, this.componentContentIndex)
66      })
67      Button("Increment arrayIndex: " + this.arrayIndex).onClick(()=>{
68        ++this.arrayIndex
69      })
70      Button("Decrement arrayIndex: " + this.arrayIndex).onClick(()=>{
71        --this.arrayIndex
72      })
73      Button("Delete ComponentContent" + this.arrayIndex).onClick(()=>{
74        if (this.arrayIndex >= 0 && this.arrayIndex < this.contentArray.length) {
75          let componentContent = this.contentArray.splice(this.arrayIndex, 1)
76          this.overlayNode.removeComponentContent(componentContent.pop())
77        } else {
78          console.info("Invalid arrayIndex.")
79        }
80      })
81      Button("Show ComponentContent" + this.arrayIndex).onClick(()=>{
82        if (this.arrayIndex >= 0 && this.arrayIndex < this.contentArray.length) {
83          let componentContent = this.contentArray[this.arrayIndex]
84          this.overlayNode.showComponentContent(componentContent)
85        } else {
86          console.info("Invalid arrayIndex.")
87        }
88      })
89      Button("Hide ComponentContent" + this.arrayIndex).onClick(()=>{
90        if (this.arrayIndex >= 0 && this.arrayIndex < this.contentArray.length) {
91          let componentContent = this.contentArray[this.arrayIndex]
92          this.overlayNode.hideComponentContent(componentContent)
93        } else {
94          console.info("Invalid arrayIndex.")
95        }
96      })
97      Button("Show All ComponentContent").onClick(()=>{
98          this.overlayNode.showAllComponentContents()
99      })
100      Button("Hide All ComponentContent").onClick(()=>{
101        this.overlayNode.hideAllComponentContents()
102      })
103
104      Button("Go").onClick(()=>{
105        router.pushUrl({
106          url: 'pages/Second'
107        })
108      })
109    }
110    .width('100%')
111    .height('100%')
112  }
113}
114```
115![overlayManager-demo1](figures/overlaymanager-demo_1.gif)
116
117The following example shows how to display a floating bubble that always stays on the left side of the screen, and clicking it displays an alert dialog box.
118
119```ts
120import { ComponentContent, OverlayManager } from '@kit.ArkUI';
121
122class Params {
123  context: UIContext
124  offset: Position
125  constructor(context: UIContext, offset: Position) {
126    this.context = context
127    this.offset = offset
128  }
129}
130@Builder
131function builderOverlay(params: Params) {
132  Column() {
133    Stack(){
134    }.width(50).height(50).backgroundColor(Color.Yellow).position(params.offset).borderRadius(50)
135    .onClick(() => {
136      params.context.showAlertDialog(
137        {
138          title: 'title',
139          message: 'Text',
140          autoCancel: true,
141          alignment: DialogAlignment.Center,
142          gridCount: 3,
143          confirm: {
144            value: 'Button',
145            action: () => {}
146          },
147          cancel: () => {}
148        }
149      )
150    })
151  }.focusable(false).width('100%').height('100%').hitTestBehavior(HitTestMode.Transparent)
152}
153
154@Entry
155@Component
156struct OverlayExample {
157  @State message: string = 'ComponentContent';
158  private uiContext: UIContext = this.getUIContext()
159  private overlayNode: OverlayManager = this.uiContext.getOverlayManager()
160  private overlayContent:ComponentContent<Params>[] = []
161  controller: TextInputController = new TextInputController()
162
163  aboutToAppear(): void {
164    let uiContext = this.getUIContext();
165    let componentContent = new ComponentContent(
166      this.uiContext, wrapBuilder<[Params]>(builderOverlay),
167      new Params(uiContext, {x:0, y: 100})
168    )
169    this.overlayNode.addComponentContent(componentContent, 0)
170    this.overlayContent.push(componentContent)
171  }
172
173  aboutToDisappear(): void {
174    let componentContent = this.overlayContent.pop()
175    this.overlayNode.removeComponentContent(componentContent)
176  }
177
178  build() {
179    Column() {
180
181    }
182    .width('100%')
183    .height('100%')
184  }
185}
186
187```
188![overlayManager-demo2](figures/overlaymanager-demo_2.gif)
189
190Since API version 18, you can use the **getOverlayManager** API in **UIContext** to obtain an **OverlayManager** object. With this object you can call [addComponentContentWithOrder](../reference/apis-arkui/js-apis-arkui-UIContext.md#addcomponentcontentwithorder18) to add components to specific layers, with overlays on higher layers covering those on lower ones.
191
192```ts
193import { ComponentContent, LevelOrder, OverlayManager } from '@kit.ArkUI';
194
195class Params {
196  text: string = ""
197  offset: Position
198  constructor(text: string, offset: Position) {
199    this.text = text
200    this.offset = offset
201  }
202}
203
204@Builder
205function builderTopText(params: Params) {
206  Column() {
207    Stack(){
208      Text(params.text)
209        .fontSize(30)
210        .fontWeight(FontWeight.Bold)
211    }.width(300).height(200).padding(5).backgroundColor('#F7F7F7').alignContent(Alignment.Top)
212  }.offset(params.offset)
213}
214
215@Builder
216function builderNormalText(params: Params) {
217  Column() {
218    Stack(){
219      Text(params.text)
220        .fontSize(30)
221        .fontWeight(FontWeight.Bold)
222    }.width(300).height(400).padding(5).backgroundColor('#D5D5D5').alignContent(Alignment.Top)
223  }.offset(params.offset)
224}
225
226@Entry
227@Component
228struct Index {
229  private ctx: UIContext = this.getUIContext()
230  private overlayManager: OverlayManager = this.ctx.getOverlayManager()
231  @StorageLink('contentArray') contentArray: ComponentContent<Params>[] = []
232  @StorageLink('componentContentIndex') componentContentIndex: number = 0
233  @StorageLink('arrayIndex') arrayIndex: number = 0
234  @StorageLink('componentOffset') componentOffset: Position = {x: 0, y: 80}
235
236  build() {
237    Row() {
238      Column({ space: 5 }) {
239        Button('Open Top-Level Dialog Box')
240          .onClick(() => {
241            let componentContent = new ComponentContent(
242              this.ctx, wrapBuilder<[Params]>(builderTopText),
243              new Params('I am a top-level dialog box', this.componentOffset)
244            )
245            this.contentArray.push(componentContent)
246            this.overlayManager.addComponentContentWithOrder(componentContent, LevelOrder.clamp(100000))
247          })
248        Button('Open Normal Dialog Box')
249          .onClick(() => {
250            let componentContent = new ComponentContent(
251              this.ctx, wrapBuilder<[Params]>(builderNormalText),
252              new Params('I am a normal dialog box', this.componentOffset)
253            )
254            this.contentArray.push(componentContent)
255            this.overlayManager.addComponentContentWithOrder(componentContent, LevelOrder.clamp(0))
256          })
257        Button("Remove Dialog Box").onClick(()=>{
258          if (this.arrayIndex >= 0 && this.arrayIndex < this.contentArray.length) {
259            let componentContent = this.contentArray.splice(this.arrayIndex, 1)
260            this.overlayManager.removeComponentContent(componentContent.pop())
261          } else {
262            console.info("Invalid arrayIndex.")
263          }
264        })
265      }.width('100%')
266    }
267  }
268}
269```
270
271