问题现象
如何使用openCustomDialog实现一个从外部传参的菜单弹窗,并且可以在外部监听菜单项的选中状态。
效果预览
点击放大
背景知识
不依赖UI组件的全局自定义弹出框 (openCustomDialog)存在两种入参方式创建自定义弹出框,ComponentContent和Builder:
ComponentContent封装内容可以与UI界面解耦,调用更加灵活。
使用Builder的方式,必须要与上下文做绑定,与UI存在一定耦合,具体请参考:不依赖UI组件的全局自定义弹出框 (openCustomDialog)的说明部分和@Builder装饰器使用说明。
解决方案
参考完整示例实现弹窗工具类,其核心是以下属性的具体实现:
ctx:获取UI上下文用于实现弹窗服务。
contentNode:构建弹窗的内容节点,其中弹窗中菜单项的个数,内容和传给外部监听的回调通过Params类型的数组传递。
options:弹窗的配置选项,如位置、样式、动画等。
export class CustomerPromptAction {
static ctx: UIContext;
static contentNode: ComponentContent<Object>;
static options: promptAction.BaseDialogOptions;
// 定义方法,从外部传入上下文。
static setContext(context: UIContext) {
CustomerPromptAction.ctx = context;
}
// 配置内容节点。
static setContentNode(context: UIContext, para: Params[]) {
let contentNode: ComponentContent<Object> = new ComponentContent(context, wrapBuilder(buildText), para);
CustomerPromptAction.contentNode = contentNode;
}
// 弹窗配置项。
static setOptions(options: promptAction.BaseDialogOptions) {
CustomerPromptAction.options = options;
}
// 定义弹窗打开的方法。
static openDialog(options: promptAction.BaseDialogOptions, context: UIContext, para: Params[]) {
CustomerPromptAction.setContext(context);
CustomerPromptAction.setContentNode(context, para);
CustomerPromptAction.setOptions({ alignment: DialogAlignment.Bottom, offset: { dx: 0, dy: -20 } });
if (CustomerPromptAction.contentNode !== null) {
CustomerPromptAction.ctx.getPromptAction()
.openCustomDialog(CustomerPromptAction.contentNode, options)
.then(() => {
})
.catch(() => {
});
}
}
// 关闭弹窗。
static closeDialog() {
if (CustomerPromptAction.contentNode !== null) {
CustomerPromptAction.ctx.getPromptAction()
.closeCustomDialog(CustomerPromptAction.contentNode)
.then(() => {
})
.catch(() => {
});
}
}
}
在页面中调用弹窗。
自定义菜单项实体类,声明属性方法,并通过构造器实例化。
export class Params {
title: string = "";
iconName: Resource;
click: (index: number) => void;
constructor(title: string, iconName: Resource, click: (index: number) => void) {
this.title = title;
this.iconName = iconName;
this.click = click;
}
}
定义接收菜单项选中回调的函数,根据返回的index处理逻辑。
// 点击弹窗中按钮的回调,并根据返回的index判断逻辑。
callBack = (index: number) => {
switch (index) {
case 0:
this.getUIContext().getPromptAction().showToast({
message: '点击了关闭',
duration: 2000
});
break;
case 1:
this.getUIContext().getPromptAction().showToast({
message: '点击了刷新',
duration: 2000
});
break;
case 2:
this.getUIContext().getPromptAction().showToast({
message: '点击了帮助',
duration: 2000
});
break;
}
};
初始化菜单数据源。
@State arr: Params[] = [
new Params('关闭', $r('app.media.startIcon'), this.callBack),
new Params('刷新', $r('app.media.startIcon'), this.callBack),
new Params('帮助', $r('app.media.startIcon'), this.callBack)];
完整示例参考如下:
CustomerPromptAction.ets。
import { ComponentContent, promptAction } from '@kit.ArkUI';
import { UIContext } from '@ohos.arkui.UIContext';
import { Params } from './Params';
@Builder
function buildText(params: Params[]) {
Column() {
Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceAround }) {
ForEach(params, (item: Params, index: number) => {
Column() {
Image(item.iconName)
.width(30)
.height(30)
.margin({ top: 20 })
.onClick(() => {
item.click(index);
});
Text(item.title)
.fontSize(15)
.margin({ top: 20 });
};
});
}
.width('100%');
Text('取消')
.margin({ top: 20 })
.height(50)
.width('100%')
.textAlign(TextAlign.Center)
.fontColor(Color.Blue)
.onClick(() => {
CustomerPromptAction.closeDialog();
});
}
.backgroundColor('#FFF0F0F0')
.width('100%')
.borderRadius(10);
}
export class CustomerPromptAction {
static ctx: UIContext;
static contentNode: ComponentContent<Object>;
static options: promptAction.BaseDialogOptions;
// 定义方法,从外部传入上下文。
static setContext(context: UIContext) {
CustomerPromptAction.ctx = context;
}
// 配置内容节点。
static setContentNode(context: UIContext, para: Params[]) {
let contentNode: ComponentContent<Object> = new ComponentContent(context, wrapBuilder(buildText), para);
CustomerPromptAction.contentNode = contentNode;
}
// 弹窗配置项。
static setOptions(options: promptAction.BaseDialogOptions) {
CustomerPromptAction.options = options;
}
// 定义弹窗打开的方法。
static openDialog(options: promptAction.BaseDialogOptions, context: UIContext, para: Params[]) {
CustomerPromptAction.setContext(context);
CustomerPromptAction.setContentNode(context, para);
CustomerPromptAction.setOptions({ alignment: DialogAlignment.Bottom, offset: { dx: 0, dy: -20 } });
if (CustomerPromptAction.contentNode !== null) {
CustomerPromptAction.ctx.getPromptAction()
.openCustomDialog(CustomerPromptAction.contentNode, options)
.then(() => {
})
.catch(() => {
});
}
}
// 关闭弹窗。
static closeDialog() {
if (CustomerPromptAction.contentNode !== null) {
CustomerPromptAction.ctx.getPromptAction()
.closeCustomDialog(CustomerPromptAction.contentNode)
.then(() => {
})
.catch(() => {
});
}
}
}
Index.ets。
import { Params } from './Params';
import { CustomerPromptAction } from './CustomerPromptAction';
@Entry
@Component
struct Index {
// 点击弹窗中按钮的回调,并根据返回的index判断逻辑。
callBack = (index: number) => {
switch (index) {
case 0:
this.getUIContext().getPromptAction().showToast({
message: '点击了关闭',
duration: 2000
});
break;
case 1:
this.getUIContext().getPromptAction().showToast({
message: '点击了刷新',
duration: 2000
});
break;
case 2:
this.getUIContext().getPromptAction().showToast({
message: '点击了帮助',
duration: 2000
});
break;
}
};
// 初始化弹窗菜单的数据源。
@State arr: Params[] = [
new Params('关闭', $r('app.media.startIcon'), this.callBack),
new Params('刷新', $r('app.media.startIcon'), this.callBack),
new Params('帮助', $r('app.media.startIcon'), this.callBack)];
build() {
Row() {
Column() {
Button('横向菜单')
.margin({ top: 50 })
.onClick(() => {
CustomerPromptAction.openDialog({
alignment: DialogAlignment.Bottom,
offset: { dx: 0, dy: -20 }
}, this.getUIContext(), this.arr);
});
}
.width('100%')
.height('100%');
}
.height('100%');
}
}
Params.ets。
export class Params {
title: string = "";
iconName: Resource;
click: (index: number) => void;
constructor(title: string, iconName: Resource, click: (index: number) => void) {
this.title = title;
this.iconName = iconName;
this.click = click;
}
}
https://pastebin.com/epc9DuYu
https://pastebin.com/CErz3YL5
https://pastebin.com/6YfF0p9z
https://pastebin.com/kvpAvpdi
https://pastebin.com/X9fq64a2
https://pastebin.com/R0mRDZm4
https://pastebin.com/urWyLjrt
https://pastebin.com/hcKewAUE
https://pastebin.com/MjLnmvNu
https://pastebin.com/DYMeHxN4
https://pastebin.com/L5C77sX1
https://pastebin.com/rM22qRKb
https://pastebin.com/s8kwwq5k
https://pastebin.com/A6qfadrP
https://pastebin.com/PmbE57qe
https://pastebin.com/FiuhbGfN
https://pastebin.com/B2XYkbnq
https://pastebin.com/e0q36QBZ
https://pastebin.com/VwfcTkgK
https://pastebin.com/STYB1p4a
https://pastebin.com/dL8avv7N
https://pastebin.com/WgRdkJJY
https://pastebin.com/MHmf76dA
https://pastebin.com/2b2X9tbY
https://pastebin.com/uVqiYmpP
https://pastebin.com/iWFWeXfu
https://pastebin.com/tcz08Ga5
https://pastebin.com/rFqwzRhK
https://pastebin.com/bCm1D1Wj
https://pastebin.com/EWbGJZcy
https://pastebin.com/R30cJtHA
https://pastebin.com/aV9QTvJL
https://pastebin.com/EF75B0Xs
https://pastebin.com/UFQ2LwDh
https://pastebin.com/2CK4bM77
https://pastebin.com/ksCNHaF7
https://pastebin.com/k61KcBd4
https://pastebin.com/5GUXdSsP
https://pastebin.com/byn4kM9X
https://pastebin.com/nLG9ztxg
https://pastebin.com/PGrz7isp
https://pastebin.com/Jdv6Vcs1
https://pastebin.com/wc3q2WXq
https://pastebin.com/7JM3Dt9d
https://pastebin.com/PKueg3Q9
https://pastebin.com/C8hvWEnm
https://pastebin.com/nXYRTagp
https://pastebin.com/rzgJVLh2
https://pastebin.com/GXM3nwFL
https://pastebin.com/t0GkNTPB
https://pastebin.com/SGvqUZUw
https://pastebin.com/8SfWYWuA
https://pastebin.com/Cy2FKdCM
https://pastebin.com/Cwi3azHM
https://pastebin.com/WkBmAyzu
https://pastebin.com/NtcjEH8D
https://pastebin.com/vPFjfiTV
https://pastebin.com/VWQEns27
https://pastebin.com/W6sGgxN4
https://pastebin.com/BRTkHWLB
https://pastebin.com/b7kSTqmz
https://pastebin.com/TKxKXExY
https://pastebin.com/WbG5WLAC
https://pastebin.com/kNf5AwB7
https://pastebin.com/cgRrpGud
https://pastebin.com/TqFJkVxd
https://pastebin.com/Vwrjm3w7
https://pastebin.com/4ZMkzUBr
https://pastebin.com/GBW5cMYt
https://pastebin.com/RmGU8Ame
https://pastebin.com/RJ11SAm3
https://pastebin.com/kQrLCYA9
https://pastebin.com/9EH4eaY8
https://pastebin.com/YacTrPKQ
https://pastebin.com/DBYCLtGD
https://pastebin.com/y9eemXwr
https://pastebin.com/jTRFengj
https://pastebin.com/5vE7dpsX
https://pastebin.com/Kk4bZ1L8
https://pastebin.com/Kaxbk4tA
https://pastebin.com/LGR3sxN9
https://pastebin.com/2jbBiu33
https://pastebin.com/p0i2Fj9p
https://pastebin.com/uThxW0MS
https://pastebin.com/hr1MtNuu
https://pastebin.com/nt6fFaYk
https://pastebin.com/9RMs3tAN
https://pastebin.com/3pp9A2SP
https://pastebin.com/fbQQkXb2
https://pastebin.com/RNXkhP0Y
https://pastebin.com/62GMDSK1
https://pastebin.com/A47VdXsL
https://pastebin.com/TMXrdhxC
https://pastebin.com/pZV96ZWh
https://pastebin.com/BnZ4zhH2
https://pastebin.com/hqGmeuVV
https://pastebin.com/aqnxjmby
https://pastebin.com/uNxvnAFc
https://pastebin.com/tkDrfMPT
https://pastebin.com/6ufWP0fd
https://pastebin.com/H9PDFDiL
https://pastebin.com/qM9xgF7K
https://pastebin.com/iyJTH6aB
https://pastebin.com/ZiJyZLfp
https://pastebin.com/yZ0LA5dB
https://pastebin.com/8YX63tah
https://pastebin.com/v6DvRcJ2
https://pastebin.com/dQSyGA1C
https://pastebin.com/VLfUFJ3F
https://pastebin.com/1dHdGtmp
https://pastebin.com/ufJFhNjk
https://pastebin.com/t1WuAJPZ
https://pastebin.com/pZUndcCA
https://pastebin.com/ZPDUXz25
https://pastebin.com/ULjPJmEH
https://pastebin.com/EhwMqtVW
https://pastebin.com/EMCGkgwT
https://pastebin.com/60tHCxEM
https://pastebin.com/c4nYDLJs
https://pastebin.com/gQSdXcnY
https://pastebin.com/jc1GvWkA
https://pastebin.com/EVjzT0Bn
https://pastebin.com/hE2m4nfV
https://pastebin.com/yf3kYzc4
https://pastebin.com/Cj6MtRgk
https://pastebin.com/e7Hmp2wM
https://pastebin.com/0HzG8VJj
https://pastebin.com/XSTJdK3z
https://pastebin.com/mnfsGkiu
https://pastebin.com/REx1hsyn
https://pastebin.com/50VxQZdS
https://pastebin.com/0mxMQAfy
https://pastebin.com/AtGFtGFZ
https://pastebin.com/eWZmH6hX
https://pastebin.com/68JVfXcf
https://pastebin.com/Q47SWvBD
https://pastebin.com/pRR9gzGf
https://pastebin.com/KiMStGV8
https://pastebin.com/k8vp0yy7
https://pastebin.com/tN4ChEUp
https://pastebin.com/7pAZ3CdD
https://pastebin.com/rpSjghL8
https://pastebin.com/dYFDgUM2
https://pastebin.com/NQyE3NAS
https://pastebin.com/LYbXc4ma
https://pastebin.com/naCsLg7e
https://pastebin.com/YKnWCm7f
https://pastebin.com/zpSHGbnT
https://pastebin.com/qQg87Qa5
https://pastebin.com/wkijxdgV
https://pastebin.com/ASWCH7DB
https://pastebin.com/NAQqmtQW
https://pastebin.com/6QHpyMV1
https://pastebin.com/WT2xgp5n
https://pastebin.com/qnTJDwPy
https://pastebin.com/fZvEStv0
https://pastebin.com/VfxtAWJG
https://pastebin.com/vyQJKxFQ
https://pastebin.com/ExGA44gn
https://pastebin.com/qa32zS0w
https://pastebin.com/GfBS4n1X
https://pastebin.com/JhJXWrUD
https://pastebin.com/WNPAYC7r
https://pastebin.com/i77xpTm7
https://pastebin.com/jvyz7bDq
https://pastebin.com/h9iLgLDD
https://pastebin.com/0dtPxmtT
https://pastebin.com/4w2UaMSn
https://pastebin.com/Xy4S2CRs
https://pastebin.com/EHQtV6b7
https://pastebin.com/ucP8B1iB
https://pastebin.com/2Wcf2GNC
https://pastebin.com/L9SiHQ9Z
https://pastebin.com/wXCZSJuj
https://pastebin.com/vbPTR3SF
https://pastebin.com/7yxGcVHj
https://pastebin.com/MNAcjFjQ
https://pastebin.com/0A4KPjNU
https://pastebin.com/8nBAWbca
https://pastebin.com/Gh9dhxLt
https://pastebin.com/08qFJBye
https://pastebin.com/mfweHrVr
https://pastebin.com/RWwcnrYC
https://pastebin.com/anp3JpJ4
https://pastebin.com/hvBGQjK0
https://pastebin.com/EGww5k1k
https://pastebin.com/wdwGG4Mx
https://pastebin.com/qKr2rRmv
https://pastebin.com/VpBYTpBH
https://pastebin.com/Bsix0p2q
https://pastebin.com/d0rRmyuc
https://pastebin.com/1YVNhKx3
https://pastebin.com/PGscNx9F
https://pastebin.com/sE0Mv39Y
https://pastebin.com/20dhC8pa
https://pastebin.com/wGmcz5e6
https://pastebin.com/cApeLHfX
https://pastebin.com/mBT8cEji
https://pastebin.com/4hXLXigr
https://pastebin.com/fgt151cu
0 个评论
要回复文章请先登录或注册