Instantiate a button with parameter?

Hi!

I have one button that I did as prefab.

I access this prefab in my script as [SerialazeField]. I can instantiante and set the parent.

But how I will set the parameters on Click? If I have this button in the hierarchy, I just drop my script in that field below the “Runtime Only” and set my the fcuntion and set the paramenter. I have one integer as parameter…

I use this button to create a list with these buttons. This integer paramenter is used to load a model in a List

EDIT 1: If I keep this prefab button in the hierarchy objects only set active as false and use it to instantiate, is the half o path…Now to know how change the parameter…

Thank you

No, much more easy…or much easier!?!

myBtn.GetComponent().onClick.AddListener(delegate { changeModel(3); });

The way above is an excellent simple way for one button.

Sometimes you want to do more than one thing per item:

  • change name
  • change picture
  • connect listener to button?

This maybe you do when you show a grid of pictures, or grid of choices.

Enclosed is my approach: I make a custom script to control one item:

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

// @kurtdekker

public class OneSingleTile : MonoBehaviour
{
    [SerializeField]Button Button;
    [SerializeField]Text Caption;
    [SerializeField]Image Icon;

    public void SetCaptionText( string caption)
    {
        Caption.text = caption;
    }

    public void SetIconSprite (Sprite sprite)
    {
        Icon.sprite = sprite;
    }

    public void SetButtonDelegate( System.Action action)
    {
        Button.onClick.AddListener(
            delegate {
                action();
            }
        );
    }
}

then I put one item in scene, turned off, and us it to make as many as I need in a GridLayoutGroup:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// @kurtdekker

public class DynamicUIDemo : MonoBehaviour
{
    [Header("This example tile will be cloned.")]
    public OneSingleTile ExemplarTile;

    OneSingleTile MakeFreshCopyOfExampleTile()
    {
        // create it and simultaneously parent it to the same place in the UI
        var copy = Instantiate<OneSingleTile>( ExemplarTile, ExemplarTile.transform.parent);

        // make it visible
        copy.gameObject.SetActive( true);

        return copy;
    }

    void Start ()
    {
        // turn off the example first, so it doesn't interfere
        ExemplarTile.gameObject.SetActive( false);

        // you choose how to create these, perhaps from a list
        // of known levels, or a list of items, for instance.

        // This code searches Resources/DynamicUISprites and loads
        // all the sprites it finds, sorts them by alphabetical
        // name, and displays them in the grid.

        var sprites = Resources.LoadAll<Sprite>( "DynamicUISprites/");

        Debug.Log( System.String.Format( "I found {0} sprites.", sprites.Length));

        // alpha sort by name
        System.Array.Sort( sprites, (a,b) => { return a.name.CompareTo( b.name); });

        // now make buttons (tiles) out of each one
        foreach( var sprite in sprites)
        {
            var entry = MakeFreshCopyOfExampleTile();

            entry.SetIconSprite( sprite);

            entry.SetCaptionText( sprite.name);

            // set up what each button does when pressed
            {
                string textToDisplay = "You clicked on:" + sprite.name;

                entry.SetButtonDelegate(
                    () =>
                    {
                        Debug.Log( textToDisplay);

                        // TODO you can call whatever other code you like here...
                    }
                );
            }
        }
    }
}

See enclosed for full setup.

9557998–1351300–DynamicUIDemo.unitypackage (94 KB)

1 Like

What? The Kurt did a book while I was taking coffee…

Kurt, why my code doest work? The index i is the same for all buttons. And if I have 2 btns, so 0 and 1 woulb be the index but actually is 2…Is like the index i is updating for all buttons while looping…

foreach (valuesModel c in SelectedModel.listOfModels[0].selectedModelC)
{
     GameObject n =  Instantiate(buttonCVersions, panelCVersions.transform);
     print(i);
     n.transform.GetChild(0).GetComponent<TMP_Text>().text = c.titleButton;
     n.transform.GetComponent<Button>().onClick.AddListener(delegate { changeModel(i); });
     i++;
     print("ok1");
}

Ah, very common error… here is more:

Delegate / Action variable capture / value capture:

https://discussions.unity.com/t/809602/2

A very nice summary by Bunny83;

https://discussions.unity.com/t/892867/5

2 Likes

I implemented the same idea in your code and work fine!

int index = 0;
// now make buttons (tiles) out of each one
foreach( var sprite in sprites)
{
    var entry = MakeFreshCopyOfExampleTile();

    entry.SetIconSprite( sprite);

    entry.SetCaptionText( sprite.name);

    // set up what each button does when pressed
    {
        string textToDisplay = "You clicked on:" + sprite.name + " " + index;

        entry.SetButtonDelegate(
            () =>
            {
                Debug.Log( textToDisplay);

                // TODO you can call whatever other code you like here...
            }
        );
    }
    index++;

}

holly mole…Perfect that stuff Kurt…Explain very well.

Bunny sais: “So it does not read the “value” of the variable when you create the closure but actually accesses the variable itself.”

Kurt said: “C# does “variable capture” instead of value capture”…

Thank you Sir.

1 Like