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