设计一个显示消息、returns 自定义对象并等待用户响应的对话框

Designing a dialogbox that displays message, returns a custom object and waits for user response

我正在尝试为所有平台上的运行时统一设计一个自定义对话框(在我的例子中是 Android 和网络播放器)。

我已成功显示对话框并获得用户响应并更新此响应。但是我不知道如何调用显示对话框并在它之前等待 return 从其他方法外部使用它时的值/class.

这是我显示对话框的代码:

            public void ShowDialogBox(string title, string message, DialogBoxButtons buttons)
            {
                StartCoroutine(ShowDialogBoxHelper(title, message, buttons));
            }

            public void ShowDialogBox(string title, string message)
            {
                StartCoroutine(ShowDialogBoxHelper(title, message, DialogBoxButtons.OK));
            }

            public IEnumerator ShowDialogBoxHelper (string title, string message, DialogBoxButtons buttons)
            {
                Response = DialogResponse.NONE;

                Title.text = title;
                Message.text = message;

                ButtonSet = buttons;
                HandleButtonSet(ButtonSet);

                _canvasGroup.alpha = 1;
                _canvasGroup.interactable = true;
                transform.SetAsLastSibling();

                _apprearenceMode = ApprearenceMode.Shown;

                 yield return StartCoroutine(WaitForButtonResponse());

                Debug.Log("user response : " + Response);

            }

协程 "WaitForButtonResponse()" 声明如下:

IEnumerator WaitForButtonResponse()
            {
                Debug.Log("waiting in the enumerator, responded: " + Response);

                yield return new waitForUserAction(() => Response != DialogResponse.NONE);

                Debug.Log("done waiting in the enumerator, responded: " + Response);

            }

而"waitForUserAction()"协程是自定义协程,继承自CustomYieldInstruction

[System.Serializable]
    class waitForUserAction : CustomYieldInstruction
    {
        Func<bool> m_Predicate;

        public override bool keepWaiting { get { return !m_Predicate(); } }

        public waitForUserAction(Func<bool> predicate) { m_Predicate = predicate; }
    }

当我调用 ShowDialogBox 方法时,对话框按预期出现,当我单击其中一个选项时,响应已正确更新。但是,如果我希望 ShowDialogBox return 响应并等待用户在 returning 之前单击对话框按钮,我该如何实现?

期望的行为:

 public DialogResponse ShowDialogBox(string title, string message, DialogBoxButtons buttons)
            {
                StartCoroutine(ShowDialogBoxHelper(title, message, buttons));
                return Response;
            }

和这样的用法:

 if (ShowDialogBox("test", "testing dialog box behaviour", DialogBoxButtons.YES_NO_CANCEL) == DialogResponse.YES)
                {
                    //do something
                }

现在的问题是,"return Response;" 不等待 "StartCoroutine(ShowDialogBoxHelper(title, message, buttons));" 更新用户的选择并且 return 是 Response 的旧值而不是用户当前选择的值.

提前感谢您在这方面的任何帮助!

干杯,

阿尼

您无需立即评估结果,而是需要实际等待并告诉例程在出现响应时该怎么做。

我会使用 Action<DialogResponse>,例如:

// Here you can actually use an overload with optional parameter
// If you don't pass in the "buttons" it simply has the default value `OK`
// And additionally pass in the action to invoke once a response was given
// If you don't pass it then simply nothing happens ;) 
public void ShowDialogBox(string title, string message, DialogBoxButtons buttons = DialogBoxButtons.OK, Action<DialogResponse> onResponse = null)
{
    StartCoroutine(ShowDialogBoxHelper(title, message, buttons, onResponse));
}

public IEnumerator ShowDialogBoxHelper (string title, string message, DialogBoxButtons buttons, Action<DialogResponse> onResponse)
{
    Response = DialogResponse.NONE;

    Title.text = title;
    Message.text = message;

    ButtonSet = buttons;
    HandleButtonSet(ButtonSet);

    _canvasGroup.alpha = 1;
    _canvasGroup.interactable = true;
    transform.SetAsLastSibling();

    _apprearenceMode = ApprearenceMode.Shown;

    // Here rather use the Unity built-in
    yield return new WaitWhile(() => Response == DialogResponse.NONE);

    Debug.Log("user response : " + Response);

    onResponse?.Invoke(Response);
}

您可以将其与 lambda 表达式一起使用,例如

ShowDialogBox("test", "testing dialog box behaviour", DialogBoxButtons.YES_NO_CANCEL, response => 
    {
        if(response == DialogResponse.YES)
        {
            // Do something
        }
    });

或相同但有一个方法

ShowDialogBox("test", "testing dialog box behaviour", DialogBoxButtons.YES_NO_CANCEL, HandleResponse);

private void HandleResponse(DialogResponse response)
{
    if(response == DialogResponse.YES)
    {
        // Do something
    }
}