目录
不依赖UI组件的全局气泡提示 (openPopup)
弹出气泡
创建ComponentContent
绑定组件信息
设置弹出气泡样式
更新气泡样式
关闭气泡
在HAR包中使用全局气泡提示
不依赖UI组件的全局菜单 (openMenu)
弹出菜单
创建ComponentContent
绑定组件信息
设置弹出菜单样式
更新菜单样式
关闭菜单
在HAR包中使用全局菜单
Toast
使用建议
即时反馈模式对比
创建即时反馈
显示关闭即时反馈
气泡提示(Popup)在使用时依赖绑定UI组件,否则无法使用。从API version 18开始,可以通过使用全局接口openPopup的方式,在无UI组件的场景下直接或封装使用,例如在事件回调中使用或封装后对外提供能力。
通过openPopup可以弹出气泡。
promptAction.openPopup(contentNode, { id: targetId }, {
enableArrow: true
})
.then(() => {
console.info('openPopup success');
})
.catch((err: BusinessError) => {
console.error('openPopup error: ' + err.code + ' ' + err.message);
})
通过调用openPopup接口弹出其气泡,需要提供用于定义自定义弹出框的内容ComponentContent。其中,wrapBuilder(buildText)封装自定义组件,new Params(this.message)是自定义组件的入参,可以缺省,也可以传入基础数据类型。
private contentNode: ComponentContent
如果在wrapBuilder中包含其他组件(例如:Popup、Chip组件),则ComponentContent应采用带有四个参数的构造函数constructor,其中options参数应传递{ nestingBuilderSupported: true }。
@Builder
export function buildText(params: Params) {
Popup({
// 类型设置图标内容
icon: {
image: $r('app.media.app_icon'),
width: 32,
height: 32,
fillColor: Color.White,
borderRadius: 10
} as PopupIconOptions,
// 设置文字内容
title: {
text: `This is a Popup title 1`,
fontSize: 20,
fontColor: Color.Black,
fontWeight: FontWeight.Normal
} as PopupTextOptions,
// 设置文字内容
message: {
text: `This is a Popup message 1`,
fontSize: 15,
fontColor: Color.Black
} as PopupTextOptions,
// 设置按钮内容
buttons: [{
text: 'confirm',
action: () => {
console.info('confirm button click');
},
fontSize: 15,
fontColor: Color.Black,
},
{
text: 'cancel',
action: () => {
console.info('cancel button click');
},
fontSize: 15,
fontColor: Color.Black
},] as [PopupButtonOptions?, PopupButtonOptions?]
})
}
let contentNode: ComponentContent
通过调用openPopup接口弹出气泡,需要提供绑定组件的信息TargetInfo。若未传入有效的target,则无法弹出气泡。
let frameNode: FrameNode | null = this.ctx.getFrameNodeByUniqueId(this.getUniqueId());
let targetId = frameNode?.getChild(0)?.getUniqueId();
通过调用openPopup接口弹出气泡,可以设置PopupCommonOptions属性调整气泡样式。
private options: PopupCommonOptions = { enableArrow: true };
通过updatePopup可以更新气泡的样式。支持全量更新和增量更新其气泡样式,不支持更新showInSubWindow、focusable、onStateChange、onWillDismiss和transition。
promptAction.updatePopup(contentNode, {
enableArrow: false
}, true)
.then(() => {
console.info('updatePopup success');
})
.catch((err: BusinessError) => {
console.error('updatePopup error: ' + err.code + ' ' + err.message);
})
通过调用closePopup可以关闭气泡。
promptAction.closePopup(contentNode)
.then(() => {
console.info('closePopup success');
})
.catch((err: BusinessError) => {
console.error('closePopup error: ' + err.code + ' ' + err.message);
})
由于updatePopup和closePopup依赖content来更新或者关闭指定的气泡,开发者需自行维护传入的content。
以下示例通过HAR包封装一个Popup,从而对外提供气泡的弹出、更新和关闭能力。
// library/src/main/ets/components/MainPage.ets
import { BusinessError } from '@kit.BasicServicesKit';
import { ComponentContent, TargetInfo, PromptAction } from '@kit.ArkUI';
export class PromptActionClass {
private promptAction: PromptAction | null = null;
private contentNode: ComponentContent
// entry/src/main/ets/pages/Index.ets
import { PromptActionClass } from "library";
import { ComponentContent, PromptAction } from '@kit.ArkUI';
class Params {
text: string = "";
promptActionClass: PromptActionClass = new PromptActionClass();
constructor(text: string, promptActionClass: PromptActionClass) {
this.text = text;
this.promptActionClass = promptActionClass;
}
}
@Builder
function buildText(params: Params) {
Column() {
Text(params.text)
.fontSize(20)
.margin({ top: 10 })
Button('Update')
.margin({ top: 10 })
.width(100)
.onClick(() => {
params.promptActionClass.updatePopup({
enableArrow: false,
});
})
Button('Close')
.margin({ top: 10 })
.width(100)
.onClick(() => {
params.promptActionClass.closePopup();
})
}.width(130).height(150)
}
@Entry
@Component
struct Index {
@State message: string = "hello";
private uiContext: UIContext = this.getUIContext();
private promptAction: PromptAction = this.uiContext.getPromptAction();
private promptActionClass: PromptActionClass = new PromptActionClass();
private targetId: number = 0;
private contentNode: ComponentContent =
new ComponentContent(this.uiContext, wrapBuilder(buildText), new Params(this.message, this.promptActionClass));
private options: PopupCommonOptions = { enableArrow: true };
build() {
Column() {
Button("openPopup")
.margin({ top: 50, left: 100 })
.onClick(() => {
let frameNode: FrameNode | null = this.uiContext.getFrameNodeByUniqueId(this.getUniqueId());
let targetId = frameNode?.getChild(0)?.getUniqueId();
if (targetId == undefined) {
this.targetId = 0;
} else {
this.targetId = targetId;
}
this.promptActionClass.setPromptAction(this.promptAction);
this.promptActionClass.setContentNode(this.contentNode);
this.promptActionClass.setOptions(this.options);
this.promptActionClass.setIsPartialUpdate(false);
this.promptActionClass.setTarget({ id: this.targetId });
this.promptActionClass.openPopup();
})
}
}
}
菜单控制 (Menu)在使用时依赖绑定UI组件,否则无法使用。从API version 18开始,可以通过使用全局接口openMenu的方式,在无UI组件的场景下直接或封装使用,例如在事件回调中使用或封装后对外提供能力。
通过openMenu可以弹出菜单。
promptAction.openMenu(contentNode, { id: targetId }, {
enableArrow: true
})
.then(() => {
console.info('openMenu success');
})
.catch((err: BusinessError) => {
console.error('openMenu error: ' + err.code + ' ' + err.message);
})
通过调用openMenu接口弹出菜单,需要提供用于定义自定义弹出框的内容ComponentContent。其中,wrapBuilder(buildText)封装自定义组件,new Params(this.message)是自定义组件的入参,可以缺省,也可以传入基础数据类型。
private contentNode: ComponentContent = new ComponentContent(uiContext, wrapBuilder(buildText), this.message);
如果在wrapBuilder中包含其他组件(例如:Popup、Chip组件),则ComponentContent应采用带有四个参数的构造函数constructor,其中options参数应传递{ nestingBuilderSupported: true }。
@Builder
export function buildText(params: Params) {
Menu({
// 类型设置图标内容
icon: {
image: $r('app.media.app_icon'),
width: 32,
height: 32,
fillColor: Color.White,
borderRadius: 10
} as MenuIconOptions,
// 设置文字内容
title: {
text: `This is a Menu title 1`,
fontSize: 20,
fontColor: Color.Black,
fontWeight: FontWeight.Normal
} as MenuTextOptions,
// 设置文字内容
message: {
text: `This is a Menu message 1`,
fontSize: 15,
fontColor: Color.Black
} as MenuTextOptions,
// 设置按钮内容
buttons: [{
text: 'confirm',
action: () => {
console.info('confirm button click');
},
fontSize: 15,
fontColor: Color.Black,
},
{
text: 'cancel',
action: () => {
console.info('cancel button click');
},
fontSize: 15,
fontColor: Color.Black
},] as [MenuButtonOptions?, MenuButtonOptions?]
})
}
let contentNode: ComponentContent = new ComponentContent(uiContext, wrapBuilder(buildText), this.message, { nestingBuilderSupported: true });
通过调用openMenu接口弹出菜单,需要提供绑定组件的信息TargetInfo。若未传入有效的target,则无法弹出菜单。
let frameNode: FrameNode | null = this.ctx.getFrameNodeByUniqueId(this.getUniqueId());
let targetId = frameNode?.getChild(0)?.getUniqueId();
通过调用openMenu接口弹出菜单,可以设置MenuOptions属性调整菜单样式。title属性不生效。preview参数仅支持设置MenuPreviewMode类型。
private options: MenuOptions = { enableArrow: true, placement: Placement.Bottom };
通过updateMenu可以更新菜单的样式。支持全量更新和增量更新其菜单样式,不支持更新showInSubWindow、preview、previewAnimationOptions、transition、onAppear、aboutToAppear、onDisappear和aboutToDisappear。
promptAction.updateMenu(contentNode, {
enableArrow: false
}, true)
.then(() => {
console.info('updateMenu success');
})
.catch((err: BusinessError) => {
console.error('updateMenu error: ' + err.code + ' ' + err.message);
})
通过调用closeMenu可以关闭菜单。
promptAction.closeMenu(contentNode)
.then(() => {
console.info('openMenu success');
})
.catch((err: BusinessError) => {
console.error('openMenu error: ' + err.code + ' ' + err.message);
})
由于updateMenu和closeMenu依赖content来更新或者关闭指定的菜单,开发者需自行维护传入的content。
可以通过HAR包封装一个Menu,从而对外提供菜单的弹出、更新和关闭能力。
即时反馈(Toast)是一种临时性的消息提示框,用于向用户显示简短的操作反馈或状态信息。它通常在屏幕的底部或顶部短暂弹出,随后在一段时间后自动消失。即时反馈的主要目的是提供简洁、不打扰的信息反馈,避免干扰用户当前的操作流程。
可以通过使用UIContext中的getPromptAction方法获取当前UI上下文关联的PromptAction对象,再通过该对象调用showToast创建并显示文本提示框。
为了安全考虑,例如Toast恶意遮挡其他页面,Toast只能显示在当前的UI实例中,应用退出后,不会单独显示在桌面上。
即时反馈提供了两种显示模式,分别为DEFAULT(显示在应用内)、TOP_MOST(显示在应用之上)。
在TOP_MOST类型的Toast显示前,会创建一个全屏大小的子窗(手机上子窗大小和主窗大小一致),然后在该子窗上计算Toast的布局位置,最后显示在该子窗上。具体和DEFAULT模式Toast的差异如下:
差异点 | DEFAULT | TOP_MOST |
---|---|---|
是否创建子窗 | 否 | 是 |
层级 | 显示在主窗内,层级和主窗一致,一般比较低 | 显示在子窗中,一般比主窗层级高,比其他弹窗类组件层级高,比软键盘和权限弹窗层级低 |
是否避让软键盘 | 软键盘抬起时,必定上移软键盘的高度 | 软键盘抬起时,只有toast被遮挡时,才会避让,且避让后toast底部距离软键盘高度为80vp |
UIExtension内布局 | 以UIExtension为主窗中布局,对齐方式与UIExtension对齐 | 以宿主窗口为主窗中布局,对齐方式与宿主窗口对齐 |
import { promptAction } from '@kit.ArkUI';
@Entry
@Component
struct Index {
build() {
Column({ space: 10 }) {
TextInput()
Button() {
Text("DEFAULT类型Toast")
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.onClick(() => {
this.getUIContext().getPromptAction().showToast({
message: "ok,我是DEFAULT toast",
duration: 2000,
showMode: promptAction.ToastShowMode.DEFAULT,
bottom: 80
});
})
Button() {
Text("TOPMOST类型Toast")
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.onClick(() => {
this.getUIContext().getPromptAction().showToast({
message: "ok,我是TOP_MOST toast",
duration: 2000,
showMode: promptAction.ToastShowMode.TOP_MOST,
bottom: 85
});
})
}
}
}
适用于短时间内提示框自动消失的场景
import { PromptAction } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct toastExample {
private uiContext: UIContext = this.getUIContext();
private promptAction: PromptAction = this.uiContext.getPromptAction();
build() {
Column() {
Button('Show toast').fontSize(20)
.onClick(() => {
try {
this.promptAction.showToast({
message: 'Hello World',
duration: 2000
})
} catch (error) {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`showToast args error code is ${code}, message is ${message}`);
};
})
}.height('100%').width('100%').justifyContent(FlexAlign.Center)
}
}
适用于提示框提留时间较长,用户操作可以提前关闭提示框的场景。
import { LengthMetrics, PromptAction } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct toastExample {
@State toastId: number = 0;
private uiContext: UIContext = this.getUIContext();
private promptAction: PromptAction = this.uiContext.getPromptAction();
build() {
Column() {
Button('Open Toast')
.type(ButtonType.Capsule)
.height(100)
.onClick(() => {
try {
this.promptAction.openToast({
message: 'Toast Massage',
duration: 10000,
}).then((toastId: number) => {
this.toastId = toastId;
});
} catch (error) {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`OpenToast error code is ${code}, message is ${message}`);
};
})
Blank().height(50);
Button('Close Toast')
.height(100)
.type(ButtonType.Capsule)
.onClick(() => {
try {
this.promptAction.closeToast(this.toastId);
} catch (error) {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`CloseToast error code is ${code}, message is ${message}`);
};
})
}.height('100%').width('100%').justifyContent(FlexAlign.Center)
}
}