在本文,筆者將教大家使用 60 行不到的代碼實(shí)現(xiàn)一個(gè)通用的模態(tài)提示窗口(modal notification window)
前言:
在軟件工程中卵惦,提示窗口往往必不可少笔横,越多的提示代表越好的用戶體驗(yàn),那如何用最精悍的代碼纤壁,實(shí)現(xiàn)相對(duì)夠用的模態(tài)提示窗口呢雅镊?
如何量化“相對(duì)夠用”:
- 首先襟雷,能夠方便彈窗展示提示語(yǔ)
- 其次,能夠以組合形式展示 “確定”仁烹、“取消” 按鈕耸弄,并捕獲用戶的選擇。
- 然后卓缰,有按鈕的模態(tài)窗口计呈,點(diǎn)擊空白區(qū)域需要震動(dòng)消息窗口實(shí)現(xiàn)提醒。
- 接著征唬,沒(méi)有按鈕的模態(tài)窗口捌显,點(diǎn)擊空白區(qū)域關(guān)閉,或者震動(dòng)消息窗口而不關(guān)閉(由邏輯內(nèi)決定何時(shí)關(guān)閉)
- 最后总寒,這個(gè)提示彈窗最好能夠很方便的被調(diào)用扶歪、復(fù)用;拒絕回調(diào)(async摄闸、await 實(shí)現(xiàn))善镰。
演示:
在貼出細(xì)節(jié)實(shí)現(xiàn)前,先看看實(shí)際使用效果:
動(dòng)畫中的配套測(cè)試代碼年枕,是不是很簡(jiǎn)單炫欺?
using UnityEngine;
using static zFramework.UI.NotificationManager;
public class TestNotification : MonoBehaviour
{
public void ShowMessage() => _ = ShowAsync("這個(gè)消息沒(méi)有按鈕,點(diǎn)空白區(qū)域關(guān)閉"); //也可以使用 await 等待
public async void ShowAutoMessage()
{
_= ShowAsync("這個(gè)消息沒(méi)有按鈕熏兄、用戶不能關(guān)閉品洛,空白區(qū)域震窗树姨、2 秒后自動(dòng)關(guān)閉", interactable: false);
await UniTask.Delay(2000); // 也可以是其他判斷關(guān)閉提示窗的邏輯
CloseNotification();
}
public async void ShowMessageWithConfirm()
{
await ShowAsync("帶確認(rèn)按鈕的消息,點(diǎn)空白區(qū)域關(guān)閉會(huì)震窗", true);
Debug.Log($"{nameof(TestNotification)}: 點(diǎn)擊了確定按鈕毫别!");
}
public async void ShowMessageWithCancel()
{
await ShowAsync("帶取消按鈕的消息,點(diǎn)空白區(qū)域關(guān)閉會(huì)震窗", enablecancel: true);
Debug.Log($"{nameof(TestNotification)}: 點(diǎn)擊了取消按鈕典格!");
}
public async void ShowMessageWith2Button()
{
var index = await ShowAsync("這個(gè)消息有 2 個(gè)按鈕岛宦,點(diǎn)空白區(qū)域震窗", enableConfirm: true, enablecancel: true);
Debug.Log($"{nameof(TestNotification)}: 用戶點(diǎn)擊了{(lán)(index == 0 ? "確定" : "取消")}");
}
}
實(shí)現(xiàn):
先構(gòu)建一個(gè)通知 Notifacation
using DG.Tweening;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(CanvasGroup))]
public class Notification : MonoBehaviour
{
public TextMeshProUGUI text;
public Transform window;
public Button mask_button;
public Button confirm_button;
public Button cancel_button;
public CanvasGroup canvasGroup;
public void Init(string message, bool enableConfirm, bool enablecancel, bool interactable)
{
text.text = message;
confirm_button.gameObject.SetActive(interactable&&enableConfirm);
cancel_button.gameObject.SetActive(interactable && enablecancel);
mask_button.onClick.AddListener(() =>
{
if (enablecancel || enableConfirm|| !interactable)
window.DOShakePosition(0.5f, 5);
else
Destroy(gameObject);
});
canvasGroup.blocksRaycasts = false;
window.localScale = Vector3.one * 0.2f;
}
}
再實(shí)現(xiàn)一個(gè)通知管理器 NotificationManager
using Cysharp.Threading.Tasks;
using DG.Tweening;
using UnityEngine;
namespace zFramework.UI
{
public class NotificationManager : MonoBehaviour
{
public Notification notificationPrefab;
static NotificationManager instance;
static Notification notification;
void Awake() => instance = this;
public static void CloseNotification() => Destroy(notification.gameObject);
public static async UniTask<int> ShowAsync(string message, bool enableConfirm = false, bool enablecancel = false, bool interactable = true)
{
notification = Instantiate(instance.notificationPrefab, instance.transform, false);
notification.Init(message, enableConfirm, enablecancel, interactable);
notification.canvasGroup.blocksRaycasts = true;
await notification.window.DOScale(1, 0.5F);
try
{
var cancellation = notification.gameObject.GetCancellationTokenOnDestroy();
var index = await UniTask.WhenAny(notification.confirm_button.OnClickAsync(cancellation), notification.cancel_button.OnClickAsync(cancellation));
Destroy(notification.gameObject);
return index;
}
catch (System.Exception)
{
return 0;
}
}
}
}
最后 UI 配套
寫到最后:
- 功能如此完善代碼卻簡(jiǎn)約至此,夫復(fù)何求耍缴?
- 筆者使用了 Dotween砾肺、 UniTask 以及 UniTask的 Dotween擴(kuò)展,通過(guò)本文防嗡,也能更直觀感受到基于 async/await 實(shí)現(xiàn)的異步當(dāng)成同步寫的魅力变汪,可以跟回調(diào)地獄 say 拜拜了您嘞!
- 在測(cè)試代碼中蚁趁,筆者使用了
using static NotificationManager
,這是一個(gè)非常優(yōu)雅的語(yǔ)法糖裙盾,可以像使用本地方法一樣使用NotificationManager
中的公共方法或其他成員。 - 在測(cè)試代碼中他嫡,筆者使用了棄元運(yùn)算符(下劃線)番官,用于跳過(guò)等待,可以實(shí)現(xiàn)多個(gè)異步操作并行的直觀感受钢属。
- void 關(guān)鍵字在與 async await 配合使用時(shí)徘熔,一般用于做入口異步方法,也能夠保證函數(shù)簽名符合 UGUI 組件的事件所需要的方法類型淆党。
擴(kuò)展閱讀:
喜歡這篇文章嗎酷师?這一篇一定對(duì)你更有用:[Unity 3d] UIBlocker - 解決 UGUI 層級(jí)問(wèn)題的終極利器 ,在這篇文章中能夠看到 Notification 的實(shí)戰(zhàn)哦染乌!
版權(quán)所有山孔,轉(zhuǎn)載請(qǐng)注明出處..