Unity按钮OnClick AddListener问题 - 与For Each循环中的最后一项相同的回调

时间:2015-03-08 01:24:21

标签: c# loops onclick

所以我有一个脚本(Unity C#)运行一个IEnumerator函数,它生成一个答案数组,我想以列表格式呈现它们。

所以我用:

public Button QuestionButton;

void Start(){
    StartCoroutine(PresentQuestion());
}

IEnumerator PresentQuestion(){
    CurrentStage = Stage.QuestionStart;

    CurrentQuestion = "How many times do we have to do this to make it work?";
    Answers.Add ("1");
    Answers.Add ("2");
    Answers.Add ("3");
    Answers.Add ("4");

    float newY = 80.0f;
    foreach(string answer in Answers){
        newY-=65.0f;
        string locanswer = answer;
        Button btn = Instantiate(QuestionButton);
        btn.transform.position = new Vector3(225, newY, 0);
        btn.transform.SetParent(QuestionUI.transform, false);
        btn.gameObject.SetActive(true);
        btn.transform.FindChild("Text").GetComponent<Text>().text = locanswer;
        btn.onClick.AddListener(() => AnswerClicked(locanswer));
    }
    QuestionText.text = CurrentQuestion;
}

void AnswerClicked(string value){
    print (value);
}

QuestionButton是我在检查器中链接的按钮游戏对象,它实例化正常,文本设置正常,但是当我添加监听器时。

当我点击按钮时,我会在循环中获得最后一个字符串或_answer&#34;每次&#34;。

我不确定为什么每个实例化的新Button(btn)对象都不会在AnswerClicked上获得自己的Listener。有人可以解释一下吗?

仅供参考:QuestionUI是我的画布。

感谢。

更新:

此代码有效,但我之前的问题仍然存在。我将尝试使用我的实际代码进行更新。

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class Testing : MonoBehaviour {

public string CurrentQuestion;
public ArrayList Answers = new ArrayList();

public Button QuestionButton;
public GameObject QuestionUI;
public Text QuestionText;

void Start(){
    StartCoroutine(PresentQuestion());
}

IEnumerator PresentQuestion(){
    CurrentQuestion = "How many times do we have to do this to make it work?";
    Answers.Add ("1");
    Answers.Add ("2");
    Answers.Add ("3");
    Answers.Add ("4");

    float newY = 80.0f;
    foreach(string answer in Answers){
        newY-=65.0f;
        string locanswer = answer;
        Button btn = Instantiate(QuestionButton);
        btn.transform.position = new Vector3(225, newY, 0);
        btn.transform.SetParent(QuestionUI.transform, false);
        btn.gameObject.SetActive(true);
        btn.transform.FindChild("Text").GetComponent<Text>().text = locanswer;
        btn.onClick.AddListener(() => AnswerClicked(locanswer));
    }
    QuestionText.text = CurrentQuestion;

    return null;
}

void AnswerClicked(string value){
    print (value);
}
}

5 个答案:

答案 0 :(得分:2)

我遇到了同样的问题,我发现在单独的方法中设置onClick监听器对我有用。

以下是我在这种情况下的表现方式:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class Testing : MonoBehaviour {

    public string CurrentQuestion;
    public ArrayList Answers = new ArrayList();

    public Button QuestionButton;
    public GameObject QuestionUI;
    public Text QuestionText;

    void Start(){
        StartCoroutine(PresentQuestion());
    }

    IEnumerator PresentQuestion(){
        CurrentQuestion = "How many times do we have to do this to make it work?";
        Answers.Add ("1");
        Answers.Add ("2");
        Answers.Add ("3");
        Answers.Add ("4");

        float newY = 80.0f;
        foreach(string answer in Answers){
            newY-=65.0f;
            Button btn = Instantiate(QuestionButton);
            btn.transform.position = new Vector3(225, newY, 0);
            btn.transform.SetParent(QuestionUI.transform, false);
            btn.gameObject.SetActive(true);
            btn.transform.FindChild("Text").GetComponent<Text>().text = locanswer;
            SetButtonOnClick(btn, answer);
        }
        QuestionText.text = CurrentQuestion;

        return null;
    }

    void SetButtonOnClickAnswer(Button button, string value){
        button.onClick.AddListener(() => AnswerClicked(value));
    }

    void AnswerClicked(string value){
        print (value);
    }
}

(免责声明:我没有对此进行测试,但我在项目中运行的代码非常相似,这解决了这个问题。)

答案 1 :(得分:1)

不确定这个问题是否太老而无法回答。

我遇到了同样的问题,这就是我为使代码工作所做的事情:

  1. 将循环重构为自己的方法返回void
  2. 将foreach更改为常规for循环
  3. 这两个步骤都很重要,如果你只做其中一个步骤,那就不行了。

答案 2 :(得分:0)

好的,所以我从IEnumerator函数中删除了实例化然后回答,奇怪的是它开始工作了。

我最终得到了类似的东西:

// Use this for initialization
void Start () {
    QuestionUI.SetActive (false);
    StartCoroutine(PresentQuestion ());
}

IEnumerator PresentQuestion(){
    CurrentStage = Stage.QuestionStart;

    CurrentQuestionCard = Instantiate (QuestionCard);
    CurrentQuestionCard.GetComponent<QuestionCard> ().MoveCardToPosition (QuestionSlot);

    yield return new WaitForSeconds(3);

    ShowQuestion ();
}

void ShowQuestion(){
    QuestionUI.SetActive (true);

    QuestionUI.SetActive (true);
    CurrentQuestion = "How many times do we have to do this to make it work?";
    Answers.Add ("1");
    Answers.Add ("2");
    Answers.Add ("3");
    Answers.Add ("4");

    float newY = 80.0f;
    foreach(string answer in Answers){
        newY-=65.0f;
        string locanswer = answer;
        Button btn = Instantiate(QuestionButton);
        btn.transform.position = new Vector3(225, newY, 0);
        btn.transform.SetParent(QuestionUI.transform, false);
        btn.gameObject.SetActive(true);
        btn.transform.FindChild("Text").GetComponent<Text>().text = locanswer;
        btn.onClick.AddListener(() => AnswerClicked(locanswer));
    }
    QuestionText.text = CurrentQuestion;
}

void AnswerClicked(string value){
    print (value);
}

答案 3 :(得分:0)

这就是我遇到同样问题时我的代码所做的工作。 (尝试根据一些GameObjects列表创建一组按钮,这些游戏对象是某些父GameObject的子节点,其中每个按钮在执行此创建的脚本时单击时会响应一些函数,其中一个参数引用它应该工作的对象用。)

将“foreach”循环更改为常规for循环。如下所示:

for(int i=0;i<here.transform.childCount;i++)
{
    Transform child = here.transform.GetChild(i);
    Button new_button = (Button) Instantiate(bCharacter,transform.position,transform.rotation);
    new_button.GetComponentInChildren<Text>().text = child.name;
    new_button.transform.SetParent(panel_people.transform,false);
    new_button.onClick.AddListener( () => LookAtObject(child.gameObject) );
}

我很生气,我不知道为什么这个改变有效,使它成为伏都教解决方案,但它确实解决了每个具有正确名称的按钮的相同问题,但反应好像链接到最后一项集。

答案 4 :(得分:0)

我明白了。如果您正在为该按钮添加父级的游戏对象上没有“Canvas Renderer”组件,则该按钮将不起作用。只需将一个画布渲染器添加到按钮的父游戏对象中,它就可以使用

button.onClick.AddListener(() => MyMethod(myArg));