paul p
paul p

Reputation: 450

Unity Reusing Ui element in list

I have ran into a sort of a problem in my project, I am creating a Scroll listview to show all elements present in list in screen. I am using button in panel to show list. Now When I call ShowList() it shows elements in the list.

enter image description here

But if i add some objects to list and again call ShowList() then it also make clone of previous object as instantiated objects are present.

enter image description here

To solve this I am deleting clones using Destroy() but when list contain too many item (300~400) deleting them cause lag in the game . How can I create object pool for ui button or just deactivate them.

 public class two : MonoBehaviour {

        public GameObject Button_Template;

        private List<GameName> gm = new List<GameName>();


        public void Exit()
        {
            var og = GameObject.FindGameObjectsWithTag("clone");
            for (int i = 0; i < og.Length; i++)
            {
                Destroy(og[i]);
            }
        }
        void Start()
        {   gm.Add(new GameName("1"));
            gm.Add(new GameName("2"));
            gm.Add(new GameName("3"));
            gm.Add(new GameName("4"));

            }


      public  void ShowList()
        {

            for (int i = 0 ; i < gm.Count; i++)
                {
                    GameObject go = Instantiate(Button_Template) as GameObject;
                    go.SetActive(true);
                    one TB = go.GetComponent<one>();
                    TB.SetName(gm[i].GName);
                    go.transform.SetParent(Button_Template.transform.parent);
                    go.tag = "clone";
                }



        }


    }

Upvotes: 1

Views: 2055

Answers (1)

Programmer
Programmer

Reputation: 125275

List can be used to implement Object Pooling. Simply disable the GameObject when you are done using it. Re-enable it again if you want to use it again. The simple GameObject Pool script below re-implements the Instantiate and Destroy functions.

public class BUTTONPOOL : MonoBehaviour
{

    GameObject buttonPrefab;
    List<GameObject> buttonPool;
    bool ready = false;

    public void createButtonPool(GameObject buttonPrefab, int amount = 400)
    {
        if (ready)
        {
            Debug.LogError("createButtonPool can only be called once");
            return;
        }

        this.buttonPrefab = buttonPrefab;

        //Create 400 Buttons
        buttonPool = new List<GameObject>();
        for (int i = 0; i < amount; i++)
        {
            buttonPool.Add(Instantiate(this.buttonPrefab) as GameObject);
        }
        ready = true;
    }

    //Creates/Enables single Button
    public GameObject Instantiate()
    {
        if (!ready)
        {
            showError();
            return null;
        }

        //Return any Button that is not active
        for (int i = 0; i < buttonPool.Count; i++)
        {
            if (!buttonPool[i].activeSelf)
            {
                return buttonPool[i];
            }
        }

        //Create new Button if there is none available in the pool. Add it to the list then return it
        GameObject tempButton = Instantiate(this.buttonPrefab) as GameObject;
        buttonPool.Add(tempButton);
        return tempButton;
    }

    //Destroys/Disables single Button
    public void Destroy(GameObject button)
    {
        if (!ready)
        {
            showError();
            return;
        }
        button.SetActive(false);
    }

    //Destroys/Disables all Buttons
    public void DestroyAll()
    {
        if (!ready)
        {
            showError();
            return;
        }
        for (int i = 0; i < buttonPool.Count; i++)
        {
            if (buttonPool[i].activeSelf)
            {
                buttonPool[i].SetActive(false);
            }
        }
    }

    private void showError()
    {
        Debug.LogError("createButtonPool must be called once before any other function can be called");
    }
}

Usage:

public GameObject ButtonPrefab;
BUTTONPOOL bPool;

void test()
{
    if ((bPool = GetComponent<BUTTONPOOL>()) == null)
    {
        gameObject.AddComponent<BUTTONPOOL>();
        bPool = GetComponent<BUTTONPOOL>();
    }

    //Initiate with 300 Buttons
    bPool.createButtonPool(ButtonPrefab, 50);

    GameObject tempButton = bPool.Instantiate();

    //MUST SET BUTTON ACTIVE CALLING Instantiate()
    tempButton.SetActive(true);

    //You can do other things with the button
     one TB = tempButton.GetComponent<one>();

    //To destroy that single button
    bPool.Destroy(tempButton);

    //OR destroy that all button
    bPool.DestroyAll();
}

Note that you must set the Button to active after calling the custom Instantiate() function from the BUTTONPOOL script.

Upvotes: 1

Related Questions