HarmonyOS 鸿蒙Next求类似toast的红色错误信息提示框

发布于 1周前 作者 yibo5220 来自 鸿蒙OS

HarmonyOS 鸿蒙Next求类似toast的红色错误信息提示框

现有的toast弹窗改变不了背景色,我需要一个红色的起到错误提示错误的弹窗,弹出后过几秒再消失。

还有toast一次执行显示一个,需要能够同时显示多个错误弹窗,按照出现的顺序先后消失,网页端看到过类似的功能。



关于HarmonyOS 鸿蒙Next求类似toast的红色错误信息提示框的问题,您也可以访问:https://www.itying.com/category-93-b0.html 联系官网客服。

15 回复

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

我写了一个,看下是不是你要的效果。

cke_170.gif

src/main/ets/common/MyPromptActionUtil.ets

import { ComponentContent, PromptAction, window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

// MyPromptInfo 类用于生成唯一的 dialogID export class MyPromptInfo { public dialogID: string

constructor() { this.dialogID = this.generateRandomString(10) }

// 生成指定长度的随机字符串 generateRandomString(length: number): string { const characters = ‘abcdefghijklmnopqrstuvwxyz0123456789’; let result = ‘’;

<span class="hljs-keyword"><span class="hljs-keyword">for</span></span> (<span class="hljs-keyword"><span class="hljs-keyword">let</span></span> i = <span class="hljs-number"><span class="hljs-number">0</span></span>; i &lt; length; i++) {
  <span class="hljs-keyword"><span class="hljs-keyword">const</span></span> randomIndex = <span class="hljs-built_in"><span class="hljs-built_in">Math</span></span>.floor(<span class="hljs-built_in"><span class="hljs-built_in">Math</span></span>.random() * characters.length);
  result += characters.charAt(randomIndex);
}

<span class="hljs-keyword"><span class="hljs-keyword">return</span></span> result;

} }

// MyPromptActionUtil 类用于封装弹窗操作 export class MyPromptActionUtil<T extends MyPromptInfo> { static myDialogPromptActionUtil: MyPromptActionUtil<MyToastInfo> | undefined = undefined

public static showToast(message: string) { if (!MyPromptActionUtil.myDialogPromptActionUtil) { //当前页面没显示toast // getContext().eventHub.off(MyPromptActionUtil.myDialogPromptActionUtil?.dialogID) // MyPromptActionUtil.myDialogPromptActionUtil?.closeCustomDialog() //如果之前有的toast对话框,并且正在显示,则先关闭toast提示 window.getLastWindow(getContext()).then((windowClass) => { const uiContext = windowClass.getUIContext() MyPromptActionUtil.myDialogPromptActionUtil = new MyPromptActionUtil<MyToastInfo>(uiContext, wrapBuilder(myToastView), new MyToastInfo(message)) .setModal(false)//true:存在黑色半透明蒙层,false:没有蒙层 .setSwipeBackEnabled(false)//true:侧滑允许关闭弹窗 .setMaskTapToCloseEnabled(true)//true:点击半透明蒙层可关闭弹窗【注:如果setModal(false),那么就没有蒙层,所以点击对话框外也没有响应事件,也就是这里设置了也没效果,并且事件会穿透】 .setAlignment(DialogAlignment.Center) .onWillAppear(() => { console.info(‘在对话框的打开动画开始之前调用的回调函数’) getContext().eventHub.on(MyPromptActionUtil.myDialogPromptActionUtil?.dialogID, (data: string) => { //监听结果 if (data == ‘关闭弹窗’) { MyPromptActionUtil.myDialogPromptActionUtil?.closeCustomDialog() } }) }) .onWillDisappear(() => { console.info(‘在对话框的关闭动画开始之前调用的回调函数’) getContext().eventHub.off(MyPromptActionUtil.myDialogPromptActionUtil?.dialogID) MyPromptActionUtil.myDialogPromptActionUtil = undefined }) .showCustomDialog() }) } else { //当前正在显示toast getContext().eventHub.emit(MyPromptActionUtil.myDialogPromptActionUtil.dialogID, { msg: message }) }

}

private uiContext: UIContext; private promptAction: PromptAction; private contentNode: ComponentContent<T> | undefined; private wrapBuilder: WrappedBuilder<[T]>; private t: T; private isModal: boolean = true; private alignment: DialogAlignment = DialogAlignment.Center; private isSwipeBackEnabled: boolean = true; private isMaskTapToCloseEnabled: boolean = true; public dialogID: string

constructor(uiContext: UIContext, wrapBuilder: WrappedBuilder<[T]>, t: T) { this.uiContext = uiContext; this.promptAction = uiContext.getPromptAction(); this.wrapBuilder = wrapBuilder; this.t = t; this.dialogID = t.dialogID }

setSwipeBackEnabled(isSwipeBackEnabled: boolean) { this.isSwipeBackEnabled = isSwipeBackEnabled; return this; }

setMaskTapToCloseEnabled(isMaskTapToCloseEnabled: boolean) { this.isMaskTapToCloseEnabled = isMaskTapToCloseEnabled return this; }

setAlignment(alignment: DialogAlignment) { this.alignment = alignment; return this; }

setModal(isModal: boolean) { this.isModal = isModal; return this; }

onDidAppear(callback: () => void) { this.onDidAppearCallback = callback; return this; }

onDidDisappear(callback: () => void) { this.onDidDisappearCallback = callback; return this; }

onWillAppear(callback: () => void) { this.onWillAppearCallback = callback; return this; }

onWillDisappear(callback: () => void) { this.onWillDisappearCallback = callback; return this; }

private onDidAppearCallback?: () => void; private onDidDisappearCallback?: () => void; private onWillAppearCallback?: () => void; private onWillDisappearCallback?: () => void;

closeCustomDialog() { if (this.contentNode) { this.promptAction.closeCustomDialog(this.contentNode); } return this; }

// 显示自定义弹窗 showCustomDialog() { try { if (!this.contentNode) { this.contentNode = new ComponentContent(this.uiContext, this.wrapBuilder, this.t); } this.promptAction.openCustomDialog(this.contentNode, { // 打开自定义弹窗 alignment: this.alignment, isModal: this.isModal, showInSubWindow: false, maskRect: { x: 0, y: 0, width: ‘100%’, height: ‘100%’ }, onWillDismiss: (dismissDialogAction: DismissDialogAction) => { //弹窗响应 console.info(“reason” + JSON.stringify(dismissDialogAction.reason)) console.log(“dialog onWillDismiss”) if (dismissDialogAction.reason == 0 && this.isSwipeBackEnabled) { //手势返回时,关闭弹窗。 this.promptAction.closeCustomDialog(this.contentNode) } if (dismissDialogAction.reason == 1 && this.isMaskTapToCloseEnabled) { this.promptAction.closeCustomDialog(this.contentNode) } }, onDidAppear: this.onDidAppearCallback ? this.onDidAppearCallback : () => { }, onDidDisappear: this.onDidDisappearCallback ? this.onDidDisappearCallback : () => { }, onWillAppear: this.onWillAppearCallback ? this.onWillAppearCallback : () => { }, onWillDisappear: this.onWillDisappearCallback ? this.onWillDisappearCallback : () => { }, }); } catch (error) { // 错误处理 let message = (error as BusinessError).message; let code = (error as BusinessError).code; console.error(OpenCustomDialog args error code is ${code}, message is ${message}); } return this; } }

class MyToastInfo extends MyPromptInfo { public message: string = “”

constructor(message: string) { super() this.message = message } }

@Builder function myToastView(data: MyToastInfo) { MyToastView({ dialogID: data.dialogID, message: data.message }) }

@ObservedV2 class ToastBean { message: string = “” @Trace isShow: boolean = true

constructor(message: string) { this.message = message } }

@Component struct MyToastView { @State toast_info_list: ToastBean[] = [] @Prop dialogID: string @Prop message: string

aboutToAppear(): void { this.toast_info_list.push(new ToastBean(this.message)) getContext().eventHub.on(this.dialogID, (data: object) => { if (data[‘msg’]) { this.toast_info_list.push(new ToastBean(data[‘msg’])) } }) }

build() { Column() { ForEach(this.toast_info_list, (item: ToastBean) => { Text(item.message) .fontSize(‘36lpx’) .fontColor(Color.White) .backgroundColor("#B2ff0000") .borderRadius(8) .constraintSize({ maxWidth: ‘80%’ }) .padding({ bottom: ‘28lpx’, left: ‘60lpx’, right: ‘60lpx’, top: ‘28lpx’ }) .margin(5) .visibility(item.isShow ? Visibility.Visible : Visibility.None) .onVisibleAreaChange([0.0, 1.0], (isVisible: boolean, currentRatio: number) => { console.info('Test Text isVisible: ’ + isVisible + ‘, currentRatio:’ + currentRatio) if (isVisible && currentRatio >= 1.0) { setTimeout(() => { item.isShow = false }, 2000) } })

      .animation({
        duration: <span class="hljs-number"><span class="hljs-number">200</span></span>, onFinish: () =&gt; {
          console.info(<span class="hljs-string"><span class="hljs-string">'==== onFinish'</span></span>)
          <span class="hljs-comment"><span class="hljs-comment">//动画结束后,判断数组是否已全部为隐藏状态,是的话证明所有toast内容都展示完成,可以释放全局弹窗了</span></span>
          <span class="hljs-keyword"><span class="hljs-keyword">let</span></span> isAnimAll = <span class="hljs-literal"><span class="hljs-literal">true</span></span>
          <span class="hljs-keyword"><span class="hljs-keyword">for</span></span> (<span class="hljs-keyword"><span class="hljs-keyword">let</span></span> i = <span class="hljs-number"><span class="hljs-number">0</span></span>; i &lt; <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.toast_info_list.length; i++) {
            <span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.toast_info_list[i].isShow == <span class="hljs-literal"><span class="hljs-literal">true</span></span>) { <span class="hljs-comment"><span class="hljs-comment">//至少有一个正在显示</span></span>
              isAnimAll = <span class="hljs-literal"><span class="hljs-literal">false</span></span>
              <span class="hljs-keyword"><span class="hljs-keyword">break</span></span>;
            }
          }
          <span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (isAnimAll) {
            console.info(<span class="hljs-string"><span class="hljs-string">'已展示完全部toast,为了性能,关闭弹窗释放view'</span></span>)
            getContext(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>).eventHub.emit(<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.dialogID, <span class="hljs-string"><span class="hljs-string">"关闭弹窗"</span></span>)
          }
        }
      })
      .transition(TransitionEffect.OPACITY.animation({ duration: <span class="hljs-number"><span class="hljs-number">200</span></span> }))
  })

}

} } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

src/main/ets/pages/Page01.ets

import { MyPromptActionUtil } from ‘…/common/MyPromptActionUtil’

@Entry @Component struct Page01 {

build() { Column() { Button(‘显示Toast’).onClick(() => { MyPromptActionUtil.showToast(随机数:${<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.getRandomInt(<span class="hljs-number"><span class="hljs-number">1</span></span>, <span class="hljs-number"><span class="hljs-number">100</span></span>)}) }) } .width(‘100%’) .height(‘100%’) } getRandomInt(min: number, max: number): number { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; } }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

HarmonyOS的开发者模式提供了很多实用的工具,方便我们进行调试和优化。

牛啊大佬,我之后看看

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

AlertDialog,你看看这个能满足你的需求吗

希望HarmonyOS能继续推出更多实用的功能,满足用户的不同需求。

这个和我想要的完全不搭嘎,没有背景色,无法同时出现多个。我想要的效果是接近toast的效果

要是不嫌麻烦就@CustomDialog自定义弹窗呗

自定义的话,不知道怎么实现一次出现多个提示,数量是不确定的。而且这种弹窗会遮挡页面,影响使用

如若没有合适的,其实可以考虑自定义组件,百搭

自定义的话,怎么实现一次出现多个弹窗,数量是不确定的

在自定义组件里放个List,放一个数组当做参数,根据数组内容来循环渲染

只看样式的话,目前看到ExceptionPrompt (异常提示)比较接近

cke_338.png

回到顶部