Reputation: 665
So I have a script (Unity C#) that runs an IEnumerator function that generates an array of answers and I want to present them in a list format.
So I use:
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);
}
The QuestionButton is a button gameobject I linked in the inspector and it instantiates fine, the text is set fine, but it is when I add the listener.
When I go to click on the button I get the last string or _answer in the loop "every time".
I am not sure why each new Button (btn) object that is instantiated would not get its own Listener at AnswerClicked. Can anyone please explain?
FYI: QuestionUI is my canvas.
Thanks.
UPDATE :
This code works, but my previous problem still exists. I will attempt to update with my actual code.
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);
}
}
Upvotes: 4
Views: 9790
Reputation: 5
I figured it out. If the gameobject you are parenting the button to does NOT have a "Canvas Renderer" component on it, the button will not work. Simply add a canvas renderer to the button's parent gameobject and it will work using
button.onClick.AddListener(() => MyMethod(myArg));
Upvotes: 0
Reputation: 379
I had the same issue and I found that setting the onClick listener in a separate method worked for me.
Here's how I would do it in this case:
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);
}
}
(Disclaimer: I haven't tested this but I am running a very similar code in my project and this solved the issue.)
Upvotes: 3
Reputation: 115
Here's what I did to make my code work when I had the same problem. (Trying to make a set of buttons based on a list of GameObjects that are the children of some parent GameObject, where each button reacts when clicked by having the script that does this creation call some function, with an argument referencing which object it should work with.)
Change the "foreach" loop to a regular for loop. Like so:
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) );
}
I'm annoyed that I don't know why this change works, making it a voodoo solution, but it does get around that same problem of every button having the right name but reacting as though linked to the last item in the set.
Upvotes: 0
Reputation: 51
Not sure if this question is too old to be answered.
I had kind of the same problem and here's what I did to make my code work:
Both of these steps are important, if you only do one of them, it won't work.
Upvotes: 1
Reputation: 665
Ok, so I removed the instantiating then answers from the IEnumerator function and oddly it started working.
I ended up with something like this:
// 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);
}
Upvotes: 0