- Home /
How do I make a line of text in a list interactive?
I am trying to do the following:
I have a panel that I am placing a scroll rect on and within it I want to display lines of text that a user can select with a click. On click a callback is made with the line of text that was clicked on.
An example would be a list of items randomly generated and displayed in the GUI. The user can scroll through the list and click on one of the items. The callback function receives the name of the item clicked and goes off and does something with it.
Basically I want each item to have an OnClick event, but Text does not have that interaction. I have placed a "Button script" on a Text item but I can't replicate that in code (hence my question).
Thanks for any ideas!
Instatiating prefabs and setting them up with code is the way to go. Read this first. If you still have problem figuring out how to do this, let me know. Creating UI elements from scripting
Thanks all for the replies!
$$anonymous$$mmpies not quite what I was looking for. Let's say I have a list and the contents are strings, hello_0, hello_1, hello_2, ..., hello_n. I want to display them in a panel as text but provide the ability for a user to click on one of them and I send the string as a parameter to my callback function.
I have created a prefab that is a UI Text and has a Button Script attached. But when I instantiate it the callback I placed in the prefab is not there. Further each prefab has the string of every item in the list.
So, I want the functionality of a button on a UI Text in a panel but I don't want the LOO$$anonymous$$ of the button.
Delete the background image then it becomes just text but still acts like a button.
Or I suppose do that tutorial but ins$$anonymous$$d of a button use Text, and add an onPointerClick event to it. Not tested that though.
Yep, that's what I'm looking at now. Have to figure out how to get the callback established as it is a bit different than what I've done previously.
You should be able to use what I put in that script. If you need to access information in another script well that's what I did in that example.
The new UI does handle things differently, the Lambda that @jakovd said I should extend is different to how I'd have done things in the past. Ins$$anonymous$$d of passing a reference value back to an instance of the object the instantiating script holds the references.
Just let me know what you're struggling with and I'll help if it's something I've come across already.
Answer by jvcraft87 · Dec 29, 2014 at 07:31 AM
My GUI Canvas has a child panel I call "Item List Panel". This panel is the parent for the items that we will list. It has a script that instantiates my Text Prefab (described below).
My Text prefab I call GUI_ItemText. It is the basic UI Text object. I added an "Event Trigger (Script)" component to it, but I didn't add any event types. This prefab has another script added to it, ListItem.cs. This script builds the trigger event and has a callback in it. The code is below:
public class ListItem : MonoBehaviour {
// Use this for initialization
void Start () {
BuildTrigger();
}
// Build the trigger response
private void BuildTrigger()
{
EventTrigger eventTrigger = gameObject.GetComponent<EventTrigger>();
EventTrigger.TriggerEvent trigger = new EventTrigger.TriggerEvent();
trigger.AddListener((PointerEventData) => OnPointerClick());
EventTrigger.Entry entry = new EventTrigger.Entry()
{ callback = trigger, eventID = EventTriggerType.PointerClick };
eventTrigger.delegates.Add(entry);
}
// Called when trigger is fired
public void OnPointerClick()
{
Debug.Log("I've been clicked! " + gameObject.name);
}
}
Next I need to figure out the ScrollRect with this UI Text Objects being instantiated and laid out with the Vertical Layout Group.
Thanks all for the suggestions!
Answer by Mmmpies · Dec 28, 2014 at 09:26 AM
Did exactly this for to explain the 4.6 UI for someone recently.
Watch the @BoredMormon video Tutorial1
You don't need the Horizontal Layout Group from that video just a button with a panel underneath it with the pivot set to the top and a vertical layout group and content size filter. The video explains it all.
Then follow the second tutorial Tutorial2
All you really need from that is the idea for the prefab buttons and a headstart in the script. Don't worry too much about the script I'll post mine in a minute as an example.
EDIT:
You need the following setup in your UI
And the button has the following on it:
The button has it's own on click event but I added the Trigger Event as it could be a panel or image or any UI element.
Just give me shout if you can't get it to work.
$$anonymous$$enus script, this is the main script and attaches to the main button
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;
using System.Collections.Generic;
public class $$anonymous$$enu : $$anonymous$$onoBehaviour {
public GameObject ButtonPrefab;
public RectTransform $$anonymous$$enuPanel;
public RectTransform InfoPanel;
private BaseTypes[] _baseTypes;
private List<GameObject> menuList = new List<GameObject>();
private void Awake()
{
_baseTypes = new BaseTypes[Enum.GetValues(typeof(BaseNames)).Length];
SetupBaseNames();
}
void SetupBaseNames()
{
for(int i = 0; i < _baseTypes.Length; i++)
{
_baseTypes[i] = new BaseTypes();
_baseTypes[i].Name = ((BaseNames)i).ToString ();
}
}
// needs to be public for the event system to access it
public void $$anonymous$$enuButtonClicked()
{
if (menuList.Count == 0)
{
for(int i = 0; i < _baseTypes.Length; i++)
{
GameObject newButton = (GameObject)GameObject.Instantiate(ButtonPrefab);
newButton.GetComponentInChildren<Text>().text = _baseTypes[i].Name.ToString();
newButton.transform.SetParent($$anonymous$$enuPanel, false);
int index = i;
newButton.GetComponent<Button>().onClick.AddListener(() => {ClassButtonClicked(index);} );
Debug.Log (" menuList.Count before adding the newButton " + menuList.Count);
menuList.Add (newButton);
Debug.Log (" menuList.Count after adding the newButton " + menuList.Count);
}
}
}
public void ClassButtonClicked(int index)
{
//Debug.Log (" the selectedclass is " + _baseTypes[index].Name.ToString ());
InfoPanel.GetChild(0).GetComponent<Text>().text = _baseTypes[index].Name.ToString ();
}
public void $$anonymous$$enuExited()
{
if(menuList.Count > 0)
{
for(int i = 0; i < menuList.Count; i++)
{
Destroy(menuList[i]);
}
menuList.Clear();
}
}
}
BaseTypes script
This is just an example list of button objects.
public class BaseTypes : BaseStats {
}
public enum BaseNames {
$$anonymous$$age,
Warrior,
Archer,
$$anonymous$$onk,
Cleric,
Vampire
}
And this is the getter/setter to return the Name from that class. The original scripts were to show how to get information on the new UI from a script that does not derive from $$anonymous$$onobehaviour so probably more complex than you need.
You could just put an Array of objects in the $$anonymous$$enu Script.
public class BaseStats {
private string _name;
public BaseStats()
{
_name = "";
}
public string Name
{
get{ return _name;}
set{ _name = value;}
}
}
@$$anonymous$$mmpies, just a suggestion to make your code cleaner. In $$anonymous$$enuButtonClicked, there is no need to store that index for button and no need for ClassButtonClicked method. Just do that functionality in body of the lambda expression, where you set the listener on button click. You can put
newButton.GetComponent<Button>().onClick.AddListener(() => {newButton.GetComponent<Text>().text = "something";} );
and let the compiler do the rest. He'll know which button reference to embed in the context of that event response.
Thanks @jakovd, that is true but the tutorial I was working on is for someone to build an information panel with images, descriptions, text, stats and so on.
At the moment it only shows the name text in the child of the InfoPanel. It's just an example but in reality would be a lot more complex so I was showing it that way because it'll be far more readable than pushing all that in a Lambda expression.
Not sure on the stats is Lambda significantly cheaper than sending a reference index to another function? That's a genuine question, I'd really like to know if it is.
Your answer
![](https://koobas.hobune.stream/wayback/20220613175023im_/https://answers.unity.com/themes/thub/images/avi.jpg)