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 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 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 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