1# 设置浮层(OverlayManager) 2<!--Kit: ArkUI--> 3<!--Subsystem: ArkUI--> 4<!--Owner: @liyi0309--> 5<!--Designer: @liyi0309--> 6<!--Tester: @lxl007--> 7<!--Adviser: @HelloCrease--> 8 9浮层(OverlayManager)用于在页面(Page)之上展示自定义的UI内容,位于Dialog、Popup、Menu、BindSheet、BindContentCover和Toast等组件之下,展示范围为当前窗口的安全区内,适用于常驻悬浮等场景。 10 11 12 13可以通过使用[UIContext](../reference/apis-arkui/arkts-apis-uicontext-uicontext.md)中的[getOverlayManager](../reference/apis-arkui/arkts-apis-uicontext-uicontext.md#getoverlaymanager12)方法获取当前UI上下文关联的[OverlayManager](../reference/apis-arkui/arkts-apis-uicontext-overlaymanager.md)对象,再通过该对象调用对应方法。 14 15## 规格约束 16 17* OverlayManager上节点的层级在Page页面层级之上,在Dialog、Popup、Menu、BindSheet、BindContentCover和Toast等组件之下。 18* OverlayManager添加的节点显示和消失时没有默认动画。 19* OverlayManager上节点安全区域内外的绘制方式与Page一致,键盘避让方式与Page一致。 20* 推荐使用AppStorage存储与OverlayManager相关的属性,以避免页面切换时属性值变化导致业务错误。 21* 当使用API version 19以下版本时,OverlayManager不支持侧滑(左滑/右滑)关闭,需在[onBackPress](../reference/apis-arkui/arkui-ts/ts-custom-component-lifecycle.md#onbackpress)中添加OverlayManager关闭的逻辑。API 19及以上版本可通过配置[OverlayManagerOptions](../reference/apis-arkui/arkts-apis-uicontext-i.md#overlaymanageroptions15)中的enableBackPressedEvent属性设置OverlayManager是否响应侧滑手势。 22* OverlayManager中的事件机制优先被WrappedBuilder装饰的组件接收。若需实现浮层底部接收事件,可通过设置hitTestBehavior为HitTestMode.Transparent将事件传递至底层。 23 24## 设置浮层 25 26在OverlayManager上[新增指定节点(addComponentContent)](../reference/apis-arkui/arkts-apis-uicontext-overlaymanager.md#addcomponentcontent12)、[删除指定节点(removeComponentContent)](../reference/apis-arkui/arkts-apis-uicontext-overlaymanager.md#removecomponentcontent12)、[显示所有节点(showAllComponentContents)](../reference/apis-arkui/arkts-apis-uicontext-overlaymanager.md#showallcomponentcontents12)和[隐藏所有节点(hideAllComponentContents)](../reference/apis-arkui/arkts-apis-uicontext-overlaymanager.md#hideallcomponentcontents12)。 27 28```ts 29import { ComponentContent, OverlayManager } from '@kit.ArkUI'; 30 31class Params { 32 text: string = ""; 33 offset: Position; 34 35 constructor(text: string, offset: Position) { 36 this.text = text; 37 this.offset = offset; 38 } 39} 40 41@Builder 42function builderText(params: Params) { 43 Column() { 44 Text(params.text) 45 .fontSize(30) 46 .fontWeight(FontWeight.Bold) 47 }.offset(params.offset) 48} 49 50function initOverlayNode(uiContext: UIContext): OverlayManager { 51 uiContext.setOverlayManagerOptions({ 52 enableBackPressedEvent: true 53 }); 54 return uiContext.getOverlayManager(); 55} 56 57@Entry 58@Component 59struct OverlayExample { 60 @State message: string = 'ComponentContent'; 61 private uiContext: UIContext = this.getUIContext(); 62 private overlayNode: OverlayManager = this.uiContext.getOverlayManager(); 63 @StorageLink('contentArray') contentArray: ComponentContent<Params>[] = []; 64 @StorageLink('componentContentIndex') componentContentIndex: number = 0; 65 @StorageLink('arrayIndex') arrayIndex: number = 0; 66 @StorageLink("componentOffset") componentOffset: Position = { x: 0, y: 30 }; 67 68 build() { 69 Column({ space: 10 }) { 70 Button("递增componentContentIndex: " + this.componentContentIndex).onClick(() => { 71 ++this.componentContentIndex; 72 }) 73 Button("递减componentContentIndex: " + this.componentContentIndex).onClick(() => { 74 --this.componentContentIndex; 75 }) 76 Button("增加ComponentContent" + this.contentArray.length).onClick(() => { 77 let componentContent = new ComponentContent( 78 this.uiContext, wrapBuilder<[Params]>(builderText), 79 new Params(this.message + (this.contentArray.length), this.componentOffset) 80 ); 81 this.contentArray.push(componentContent); 82 this.overlayNode.addComponentContent(componentContent, this.componentContentIndex); 83 }) 84 Button("递增arrayIndex: " + this.arrayIndex).onClick(() => { 85 ++this.arrayIndex; 86 }) 87 Button("递减arrayIndex: " + this.arrayIndex).onClick(() => { 88 --this.arrayIndex; 89 }) 90 Button("删除ComponentContent" + this.arrayIndex).onClick(() => { 91 if (this.arrayIndex >= 0 && this.arrayIndex < this.contentArray.length) { 92 let componentContent = this.contentArray.splice(this.arrayIndex, 1); 93 this.overlayNode.removeComponentContent(componentContent.pop()); 94 } else { 95 console.info("arrayIndex有误"); 96 } 97 }) 98 Button("显示ComponentContent" + this.arrayIndex).onClick(() => { 99 if (this.arrayIndex >= 0 && this.arrayIndex < this.contentArray.length) { 100 let componentContent = this.contentArray[this.arrayIndex]; 101 this.overlayNode.showComponentContent(componentContent); 102 } else { 103 console.info("arrayIndex有误"); 104 } 105 }) 106 Button("隐藏ComponentContent" + this.arrayIndex).onClick(() => { 107 if (this.arrayIndex >= 0 && this.arrayIndex < this.contentArray.length) { 108 let componentContent = this.contentArray[this.arrayIndex]; 109 this.overlayNode.hideComponentContent(componentContent); 110 } else { 111 console.info("arrayIndex有误"); 112 } 113 }) 114 Button("显示所有ComponentContent").onClick(() => { 115 this.overlayNode.showAllComponentContents(); 116 }) 117 Button("隐藏所有ComponentContent").onClick(() => { 118 this.overlayNode.hideAllComponentContents(); 119 }) 120 121 Button("跳转页面").onClick(() => { 122 this.getUIContext().getRouter().pushUrl({ 123 url: 'pages/Second' 124 }) 125 }) 126 } 127 .width('100%') 128 .height('100%') 129 } 130} 131``` 132 133 134显示一个始终在屏幕左侧的悬浮球,点击可以弹出alertDialog弹窗。 135 136```ts 137import { ComponentContent, OverlayManager } from '@kit.ArkUI'; 138 139class Params { 140 context: UIContext; 141 offset: Position; 142 constructor(context: UIContext, offset: Position) { 143 this.context = context; 144 this.offset = offset; 145 } 146} 147@Builder 148function builderOverlay(params: Params) { 149 Column() { 150 Stack(){ 151 }.width(50).height(50).backgroundColor(Color.Yellow).position(params.offset).borderRadius(50) 152 .onClick(() => { 153 params.context.showAlertDialog( 154 { 155 title: 'title', 156 message: 'Text', 157 autoCancel: true, 158 alignment: DialogAlignment.Center, 159 gridCount: 3, 160 confirm: { 161 value: 'Button', 162 action: () => {} 163 }, 164 cancel: () => {} 165 } 166 ) 167 }) 168 }.focusable(false).width('100%').height('100%').hitTestBehavior(HitTestMode.Transparent) 169} 170 171@Entry 172@Component 173struct OverlayExample { 174 @State message: string = 'ComponentContent'; 175 private uiContext: UIContext = this.getUIContext(); 176 private overlayNode: OverlayManager = this.uiContext.getOverlayManager(); 177 private overlayContent:ComponentContent<Params>[] = []; 178 controller: TextInputController = new TextInputController(); 179 180 aboutToAppear(): void { 181 let uiContext = this.getUIContext(); 182 let componentContent = new ComponentContent( 183 this.uiContext, wrapBuilder<[Params]>(builderOverlay), 184 new Params(uiContext, {x:0, y: 100}) 185 ); 186 this.overlayNode.addComponentContent(componentContent, 0); 187 this.overlayContent.push(componentContent); 188 } 189 190 aboutToDisappear(): void { 191 let componentContent = this.overlayContent.pop(); 192 this.overlayNode.removeComponentContent(componentContent); 193 } 194 195 build() { 196 Column() { 197 198 } 199 .width('100%') 200 .height('100%') 201 } 202} 203 204``` 205 206 207从API version 18开始,可以通过调用UIContext中getOverlayManager方法获取OverlayManager对象,并利用该对象在指定层级上新增指定节点([addComponentContentWithOrder](../reference/apis-arkui/arkts-apis-uicontext-overlaymanager.md#addcomponentcontentwithorder18)),层次高的浮层会覆盖在层级低的浮层之上。 208 209```ts 210import { ComponentContent, LevelOrder, OverlayManager } from '@kit.ArkUI'; 211 212class Params { 213 text: string = ""; 214 offset: Position; 215 constructor(text: string, offset: Position) { 216 this.text = text; 217 this.offset = offset; 218 } 219} 220 221@Builder 222function builderTopText(params: Params) { 223 Column() { 224 Stack(){ 225 Text(params.text) 226 .fontSize(30) 227 .fontWeight(FontWeight.Bold) 228 }.width(300).height(200).padding(5).backgroundColor('#F7F7F7').alignContent(Alignment.Top) 229 }.offset(params.offset) 230} 231 232@Builder 233function builderNormalText(params: Params) { 234 Column() { 235 Stack(){ 236 Text(params.text) 237 .fontSize(30) 238 .fontWeight(FontWeight.Bold) 239 }.width(300).height(400).padding(5).backgroundColor('#D5D5D5').alignContent(Alignment.Top) 240 }.offset(params.offset) 241} 242 243@Entry 244@Component 245struct Index { 246 private ctx: UIContext = this.getUIContext(); 247 private overlayManager: OverlayManager = this.ctx.getOverlayManager(); 248 @StorageLink('contentArray') contentArray: ComponentContent<Params>[] = []; 249 @StorageLink('componentContentIndex') componentContentIndex: number = 0; 250 @StorageLink('arrayIndex') arrayIndex: number = 0; 251 @StorageLink('componentOffset') componentOffset: Position = {x: 0, y: 80}; 252 253 build() { 254 Row() { 255 Column({ space: 5 }) { 256 Button('点击打开置顶弹窗') 257 .onClick(() => { 258 let componentContent = new ComponentContent( 259 this.ctx, wrapBuilder<[Params]>(builderTopText), 260 new Params('我是置顶弹窗', this.componentOffset) 261 ); 262 this.contentArray.push(componentContent); 263 this.overlayManager.addComponentContentWithOrder(componentContent, LevelOrder.clamp(100000)); 264 }) 265 Button('点击打开普通弹窗') 266 .onClick(() => { 267 let componentContent = new ComponentContent( 268 this.ctx, wrapBuilder<[Params]>(builderNormalText), 269 new Params('我是普通弹窗', this.componentOffset) 270 ); 271 this.contentArray.push(componentContent); 272 this.overlayManager.addComponentContentWithOrder(componentContent, LevelOrder.clamp(0)); 273 }) 274 Button("点击移除弹窗").onClick(()=>{ 275 if (this.arrayIndex >= 0 && this.arrayIndex < this.contentArray.length) { 276 let componentContent = this.contentArray.splice(this.arrayIndex, 1); 277 this.overlayManager.removeComponentContent(componentContent.pop()); 278 } else { 279 console.info("arrayIndex有误"); 280 } 281 }) 282 }.width('100%') 283 } 284 } 285} 286``` 287 288